Pro Git
Scott Chacon, Ben Straub
버전 2.1.79-4-g5b48991, 2023-01-15
Licence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê1
Scott Chacon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê2
Ben Straub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê3
바치는 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê4
사의 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê5
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê6
시작하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê8
버전 관리란?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê8
게 보는 Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê12
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê12
CLI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê15
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê16
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê19
도움보기. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê21
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê22
Git의 기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê23
Git 소 만들기. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê23
수정하고 저소에 저하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê24
히스토리 조회하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê37
돌리 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê44
모트 저. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê46
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê52
Git Alias. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê57
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê59
Git 브랜 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê60
브랜무엇인가 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê60
브랜Merge 의 기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê67
브랜관리. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê76
브랜크플로 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê78
모트 브랜. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê82
Rebase 하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê91
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê101
Git 서버 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê102
프로토콜. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê102
서버에 Git 치하기. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê106
SSH 개키 만들기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê108
서버 정하기. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê109
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê111
스마트 HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê113
GitWeb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê115
GitLab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê117
또 다른 선택, 호스팅. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê120
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê121
환경에서의 Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê122
환경에서의 크플로 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê122
프로젝트에 기여하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê125
프로젝트 관리하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê148
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê163
GitHub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê164
계정 만들고 정하기. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê164
GitHub 프로젝트에 기여하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê169
GitHub 프로젝트 관리하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê187
Organization 관리하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê200
GitHub 스크. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê204
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê213
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê214
비전 회하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê214
화형 명령 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê221
StashingCleaning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê225
내 작에 서명하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê231
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê235
히스토리 단장하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê239
Reset 히 알고 가기. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê246
Merge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê266
Rerere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê284
Git으로 버그 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê290
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê294
Bundle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê313
Replace. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê317
Credential . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê325
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê330
Git맞춤. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê331
Git 정하기. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê331
Git Attributes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê341
Git Hooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê350
정책 구현하기. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê353
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê362
Git과 여타 버전 관리 시스 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê363
Git: Client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê363
Git으로 기기. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê402
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê420
Git의 내부 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê421
Plumbing 명령과 Porcelain 명령 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê421
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê422
Git Refs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê432
Packfile. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê436
Refspec. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê439
데이터 전송 프로토콜. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê442
운영 데이터 복구 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê447
환경. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê454
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê460
부록 A: 한 환경에서 Git 사용하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê461
GUI. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê461
Visual Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê466
Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê467
Bash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê468
Zsh. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê469
Git in Powershell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê471
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê473
부록 B: Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê474
Git 명령어 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê474
Libgit2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê474
JGit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê479
go-git. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê483
부록 C: Git 명령어 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê485
와 설 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê485
프로젝트 가오기생성하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê485
냅샷 다루기. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê486
BranchMerge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê489
유하고 데이트하기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê491
보기 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê492
Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê493
Patch 하기. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê493
Email. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê494
다른 버전 관리 시스 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê495
관리 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê495
Plumbing 명령어 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê496
Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ê497
Licence
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported
License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a
letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
1
Scott Chacon
어서오세요. Pro Git 2판 입니다. Pro Git 1판이 나온지도 벌써 4년이 넘었습니다. 시간에 따라 바뀐 부분도 많지만 중요한
내용은 여전히 그대로 입니다. 하위 호환성을 지키기 위해 Git Core 팀은 열심히 노력했습니다. 핵심적인 명령과 개념은
대부분 지금도 유효합니다. Git을 둘러싼 커뮤니티를 살펴보면 많은 것들이 추가되고 수정됐습니다. Pro Git 2판은 이러한
추가된 것, 수정된 것을 다루기 위해 나왔습니다. Git을 새로 만나는 사람에게 많이 도움될 것입니다.
Pro Git 1판이 쓰여질 당시 Git은 여전히 쓰기 어렵고 하드코어 개발자 외에는 쓰는 사람이 많지 않았습니다. 주요
커뮤니티에서 Git을 사용하는 흐름이 나타나기 시작했지만 지금처럼 어디에서나 쉽게 볼 수는 없었습니다. 그 이후 거의
모든 오픈소스 커뮤니티에서 Git을 적용하기 시작했습니다. 모든 플랫폼에서 Git을 사용하기 위한 GUI가 발전했지만 특히
Windows 환경에서 IDE 지원이나 비즈니스 용도로 주목할만큼 발전했습니다. 4년전 처음 Pro Git을 쓸 땐 생각도 못한
일들이지요. 커뮤니티의 이런 새로운 개척자를 소개하는 것이 2판을 쓰는 또 다른 이유입니다.
Git을 사용하는 오픈소스 커뮤니티는 폭발적으로 늘었습니다. 이 책을 처음 쓰기 시작한 거의 5년 전(책이 실제로 나오기
까지는 시간이 좀 걸렸습니다)은 거의 알려지지 않은 Git 호스팅 웹사이트인 GitHub에서 일을 시작할 때였습니다. 책이
출판될 즈음 GitHub 사용자는 수 천명 정도였고 저를 포함 4명이서 GitHub을 운영했습니다. 서문을 쓰는 지금 GitHub
천만개가 넘는 프로젝트를 호스팅하고 있고 등록한 사용자는 5백만에 달하며 GitHub에서 일하는 사람은 230명을 넘고
있습니다. 좋든 싫든 GitHub은 오픈소스 커뮤니티에서 무시할 수 없는 존재가 됐습니다. 처음 Pro Git 책을 쓸 때에는
상상도 못했던 일입니다.
Pro Git을 처음 쓸 때 GitHub은 여러 Git 호스팅 서비스 중 하나 정도로 소개했을 뿐이었습니다. GitHub을 다루는 것이
마음이 편치 않았습니다. 그때는 커뮤니티 자원이나 내가 다니고 있는 회사에 대해서 다루는 것은 적절하지 못하다고
느꼈었습니다. 이런 고민은 계속했지만, 어느 순간 GitHubGit 커뮤니티에서 빼놓을 수 없는 존재가 되었습니다. 고민을
접고 GitHubGit 호스팅 중 예제 하나로 다루지 않고 한 부분으로 따로 만들어 GitHub이 무엇이고 어떻게 효율적으로
활용할 수 있는지 쓰기로 했습니다. Git을 배우기로 했다면 GitHub도 배우는 것이 커뮤니티에 참여하는 데 도움이 될
것입니다. 이는 자신만의 Git 호스팅을 사용하는 것보다 더 가치 있는 활동이라 생각합니다.
1판이 나오고 난 이후 크게 바뀐 또 하나는 Git 데이터를 전송하는 데 사용하는 HTTP 프로토콜이 개되었다는 입니다.
이 책 예제의 대부분은 HTTP를 사용하는 것으로 바었습니다. HTTP가 더 간합니다.
Git잘 띄지 않던 버전 관리 시스이었습니다. 하지만 지난 년 동오픈소스는 물론 용 개발 환경에서도
중요한 자지하게 됐습니다. 이 성과정은 습니다. Pro Git은 오픈소스이면서 성을 거둔 몇 안되는
서적이 됐습니다. 서 저는 무척 행복합니다.
Pro Git 2판에서 개정된 모든 내용이 여러분에게 기을 드다면 좋습니다.
2
Ben Straub
Pro Git 1판이 바로 저를 Git 세상으로 빠뜨린 놈입니다. 전에 경시스보다도 소프트어를 개발하는데
스러운 스타일의 시스입니다. 수년 동개발자로 일해왔지만, 예전보다 더 일하는 것이 즐겁습니다.
년이 지난 지금 저는 Git 개발에 기여하고 있습니다. 장 큰 Git 호스팅 회사에서 일하고 있으며 세계를 돌아다니며
사람들에게 Git을 알려주고 있습니다. Scott이 이 책의 2판에 대한 작을 제했을 때 그 시 수했습니다.
이 책 작이고 영이었습니다. 제가 도움을 은 만큼 이 책이 여러분에게도 도움이 되니다.
3
바치는 글
나의 아내 Becky 없이는 이 모험을 시작하지 못했을 것입니다. — Ben
이 책을 나의 여자들에게 바칩니다. 나의 아내 Jessica는 이 책을 쓰는 수년 동안 저를 지지해주었고, 나의 딸
Josephine은 제가 늙어서 정신이 없을 때쯤에 절 보살펴 줄 겁니다. — Scott
4
감사의 글
Pro Git 책을 오픈소스로 운영하고 있습니다. 지난 년 동수 많은 오수정이나 책 내용 경에 대한 도움을
기부 았습니다.
아래는 영문 Pro Git 오픈소스 프로젝트에 이바지한 분들입니다. 더 나은 책을 만드는 데에 도움을 주신 모든
분에게 사의 말씀을 드니다.
이거성 규철 봉훈 조현 조현태 최병훈
2yunseong Jean-Noël Avila Sarah Schneider
craftyworks
Aiden JichangJang Sean Lee
hawaii
Chan Joeun Seonghwan Lee
jaeguly
Changdae Park Jon Forrest Stephan van Maris
jay park
Changwon Choe Junggu Lee Sungmann Cho
lethee
Changwoo Park Junyeong Yim Vincent Lee
mbc9news
Chanwoong Kim Lawrence Kim Wayne Jo
paikwiki
DalHo Park Louise Corrigan Wonki Kim
sanders@oreilly.com
Danpatpang MH Kwon YongWoo Jeon
sean.lee
Gim Gyoung Jin Mike Thibodeau Yoon, Hyunho
soursop
Hoto Cocoa Pablo Schläpfer Youngho Jeong
yongjae choi
Hyeon Seop Choi Sanders Kleinfeld akanad
Jae young Yu Sangwoo Lee buo
임준
5
Introduction
자라면 Git는 데 시간은 기자할 사람일 . 자의 시간은 중요하기에 분 내로
이 책에 담긴 내용을 간히 소개한다. 아래는 이 책에 담긴 10개의 3개의 부록에 대해 간히 정한 내용이다.
1에서는 기적인 내용을 제외하고 버전 관리 시스(VCS)Git게 대무엇인지, Git생 배경과, Git이 다른
VCS무엇이 다른지, 많은 사람들이 Git을 사용하는지 대해서 알아본. 이후 Git을 다운로드하고 치하는 과정을
아본. 미리 Git있는 시스도 있다.
2에서는 기적인 Git 사용을 알아본. 80% 은 이 에서 명하는 정도로만 Git을 사용한다. 2고나면
소를 Clone 하기, 프로젝트 히스토리를 알보기, 일을 수정하고 프로젝트에 기여하기 등을 할 수 있다.
어서 가를 기고 돌아와Git사용할 수 있다.
3에서는 Git브랜치 모에 대해서 알아본. 사람들은 브랜치가 Git의 핵심 기이라고 한다. Git 브랜치를 어떻게
활용하는지 배우면 다른 VCS어떻게 다른지 알게 된다. 3고 나면 Git브랜치 없이 어떻게 살왔는지 상상할
수 없게 될 것이다.
4에서는 서버 환경에서의 Git에 대해 알아본. Git으로 협업할 때 회사은 특정 에서 사용할 Git 서버를
구축하거나 자신만의 Git 서버를 운영하고자 하는 사람에게 요한 내용이다. Git 서버를 관리하지 않고 사용하는
여러 호스팅 서비스도 소개 한다.
5에서는 다한 분환경에서의 크플로에 대해 알보고 Git으로 어떻게 크플로를 달성하는지 알아본. 5
고나면 여러 모트 저소를 고 전문가처럼 작할 수 있다. 일로도 Git 을 할 수 있고, 많은 수의 모트
브랜치나 기여 치를 다수 있다.
6에서는 GitHub 호스팅 서비스GitHub에서 제하는 도를 자세히 알아본. 가입하고 계정을 관리하는 방법부터
Git 소를 생성하고 다른 프로젝트에 기여하고 대로 기여크플로를 살펴. GitHub이 제하는 프로그래밍
한 인터이스아두가되고 살이되는 도 소개한다.
7에서는 Git의 고명령을 알아본. 때로는 위할 수도 있는 'Reset' 은 명령에 도사가 되고, 버그를 기 위해 이
탐색 을 사용하기도 한다. 히스토리를 수정하기도 하고 히스토리에서 세세하게 비전을 선택해서 작하는 등
한 고을 알아본. 7Git을 고지게 사하는 마스터로 만들어 것이다.
8에서는 Git 환경정을 입정하는 방법을 알아본. 사용자가 원하는 정책을 만들어서 Git 환경에 적용시
수 있는 스크트를 명한다. 원하는 대로 커밋 규칙을 세우고 이를 제하도록 스크트를 작성하는 예제도 소개한다.
9에서는 Git과 다른 VCS를 함사용하는 환경에 대해 알아본. Subversion 환경에서 Git라이트로 사용하는
방법이나 다른 VCS 프로젝트를 Git 프로젝트로 경하는 방법을 알아본. 아직도 많은 에서 바없이
Subversion을 사용하고 있다. 9해 이런 Subversion 서버를 써하는 환경에서도 Git이 제하는 다장점
사용하는 을 알게 된다. 다른 VCS 환경이나 프로젝트를 Git으로 환하는 방법을 터함으로써 동에게 Git
좋은지 납득시키는 데 도움이 된다.
10에서는 Git 으로 깊숙고든다. Git이 실제로 어떻게 동작하는지 이해하고 나면 주 우하고 력하게 Git
사용할 수 있게 된다. 이처럼 내부를 이해하고 나면 이제 데이터를 어떻게 다루는 것이 좋은지 객체를 다루는 모
무엇을 사용하는지 Packfile은 정히 어떻게 이루어있는지 서버 프로토콜은 어떻게 이루어있는지 하는 경지에
게 된다. 곳곳에서 어내용을 소개하다가 좀 더 은 이해가 요한 부분에서는 10을 보도록 내하고 있다.
들과는 다Git의 은한 기적인 구조를 이해하고 다면 다른 부분보다 여기 10것이다.
6
부록 A에서는 다한 환경에서 Git을 사용하는 예제를 살펴. 여러 GUI, 여러 IDE 환경에서 Git을 사용하려면 어떻게
하는지 알아본. Shell이나 Visual Studio, Eclipse 은 환경에서 Git을 어떻게 쓰는지 어보려면 부록 A를 보면
된다.
부록 B에서는 Git을 스크트로 사용하거나 libgit2JGit 은 라이로 기확장해서 사용하는 방법
아본. 맞춤 를 제작해서 사용을 해한다거나 Git의 저수요한 경우 부록 B를 살펴보면 어떻게 해
할지 을 수 있다.
마지으로 부록 C에서는 주요 Git 명령을 한꺼번에 살펴보고 각 명령을 어디서 명하고 있는지 내하고 어떻게
사용했는지를 알려. 명령이 책의 어디에서 소개되었고 어예제가 있는지 찾아볼 때 부록 C 가 유용하다.
자 이제 시작해시다.
7
시작하기
에서 명하는 것은 Git을 처음 접하는 사람에게 요한 내용이다. 저 버전 관리 에 대한 이해Git치하는
방법명하고 마지으로 Git 서버를 정하고 사용하는 방법명한다. 을 다 고 나면 Git 생 배경, Git
사용하는 이유, Git정하고 사용하는 방법을 터하게 될 것이다.
버전 관리란?
버전 관리는 무엇이고 우이것을 알아야 할까? 버전 관리 시스변화를 시간에 따라 기록했다가 나중에
특정 시의 버전을 다시 수 있는 시스이다. 이 책에서는 버전 관리하는 예제로 소프트어 소스 코드만
보여주지만, 실제로 거의 모든 컴퓨일의 버전을 관리할 수 있다.
래픽 디자이나 웹 디자이도 버전 관리 시스(VCS - Version Control System)을 사용할 수 있다. VCS로 이지나
아웃의 버전(경 이력 은 수정 내용)관리하는 것은 명하다. VCS를 사용하면 각 일을 이전 상
돌릴 수 있고, 프로젝트를 통째로 이전 상로 되돌릴 수 있고, 시간에 따라 수정 내용을 비해 볼 수 있고, 가 문제를
일으는지도 추적할 수 있고, 제 만들어인지도 알 수 있다. VCS를 사용하면 일을 어버거나
을 때도 쉽게 복구할 수 있다. 이런 모든 장점노력 없이 이용할 수 있다.
로컬 버전 관리
많은 사람은 버전을 관리하기 위해 디렉토리일을 사하는 방법(똑똑한 사람이라면 디렉토리 이름에 시간을
을 거다). 방법은 간로 자주 사용한다. 지만, 말 뭔못되기 쉽다. 하던 디렉토리를 지거나,
실수로 일을 못 고수도 있고, 사할 수도 있다.
이런 이유로 프로그래머들은 오전에 로VCS라는 걸 만들었다. VCS주 간한 데이터이스를 사용해서
일의 경 정보를 관리했다.
8
그림 1. 로컬 버전 관리.
많이 쓰는 VCS 중에 RCS(Revision Control System)라고 부는 것이 있는데 오늘까지도 아직 많은 회사가
사용하고 있다. RCS는 기적으로 Patch Set(일에서 경되는 부분)관리한다. Patch Set은 특형식
일로 저한다. 고 일Patch Set을 적용해서 모든 일을 특정 시으로 되돌릴 수 있다.
중앙집중식 버전 관리(CVCS)
프로젝트를 진행하다 보면 다른 개발자하는 경우가 많다. 때 생기는 문제를 해하기 위해 CVCS
(앙집VCS)가 개발됐다. CVS, Subversion, Perforce 은 시스일을 관리하는 서버가 도로 있고
라이트가 중서버에서 일을 받아서 사용(Checkout)한다. 수년 동이러한 시스들이 많은 사았다.
9
그림 2. 중앙집중식 버전 관리(CVCS).
CVCS 환경은 로VCS에 비해 장점이 많다. 두 누가 무엇을 하고 있는지 알 수 있다. 관리자는 가 무엇을 할지
꼼꼼하게 관리할 수 있다. 모든 라이트의 로데이터이스를 관리하는 것보다 VCS 하나를 관리하기가 훨씬 쉽다.
그러나 이 CVCS 환경은 가지 치명적인 결점이 있다. 적인 것이 중서버에 발생한 문제다. 서버가 한
시간 동다운되면 그동안 아무도 다른 사람과 협업할 수 없고 사람들이 하는 일을 백방법도 없다. 고 중
데이터이스가 있는 하드디스크에 문제가 생기면 프로젝트의 모든 히스토리는다. 물론 사람마다 하나
냅샷괜찮. VCS 시스도 이결점이 있고 이런 문제가 발생하면 모든 것을 는다.
분산 버전 관리 시스템
DVCS(버전 관리 시스)명할 차례. Git, Mecurial, Bazaar, Darcs DVCS에서의 라이트는 순히
일의 마지냅샷Checkout 하지 않는다. 소를 히스토리와 어 전부 제한다. 서버에 문제가 생기면
로 다시 작을 시작할 수 있다. 라이트 중에서 무거나 라도 서버를 원할 수 있다. Clone은 모든
데이터를 가진 진정한 백이다.
10
그림 3. 분산 버전 관리 시스템(DVCS).
게다가 대부분의 DVCS 환경에서는 모트 저소가 존재한다. 모트 저소가 많을 수도 있다. 서 사람들은 동시에
한 그과 다방법으로 협업할 수 있다. 델 같은 중앙집시스으로는 할 수 없는 크플로를 다하게
사용할 수 있다.
11
짧게 보는 Git의 역사
리네 삶라만상처럼 Git 또한 창조파괴와 활활 타오등 속에서 시작됐다.
Linux 모가 오픈소스 프로젝트다. Linux 대부분은(1991–2002) Patch와 단
일로만 관리했다. 2002년에 드디어 Linux BitKeeper라고 불리는 상용 DVCS를 사용하기 시작했다.
2005년에 커뮤니티가 만드는 Linux 과 이을 추하는 회사가 개발한 BitKeeper계는 .
BitKeeper의 무사용이 재고된 것이다. 이 사Linux 개발 커뮤니티(특히 Linux 시자 Linus Torvalds)가 자
를 만드는 계기가 됐다. GitBitKeeper를 사용하면서 배운 교훈을 기아래와 같은 목를 세.
른 속도
순한 구조
선형적인 개발(수천 개의 동시 다발적인 브랜)
완벽한 분
Linux 은 대프로젝트에도 유용할 것(속도나 데이터 크기 면에서)
Git2005생하고 나서 아직기 목를 그대로 유지하고 있다. 그러면서도 사용하기 쉽게 진화하고 성했다.
Git친 듯라서 대프로젝트에 사용하기도 좋다. Git은 동시다발적인 브랜치에도 끄떡없는 퍼 울트라 브랜
시스이다(Git 브랜 참고).
Git 기초
Git의 핵심은 ? 이 질문은 Git을 이해하는데 히 중요하다. Git이 무엇이고 어떻게 동작하는지 이해한다면 쉽게
Git을 효과적으로 사용할 수 있다. Git을 배우려면 Subversion이나 Perforce 은 다른 VCS를 사용하던 경을 버려
한다. Git하게 달라서 다른 VCS에서 쓰던 개념으로는 갈린. 사용자 인터이스는 우 비하지만, 정보를
하는 방식이 다. 이런 을 이해하면 Git을 사용하는 것이 어렵지 않다.
차이가 아니라 스냅샷
SubversionSubversion 들과 Git의 가장 큰 차은 데이터를 다루는 방법에 있다. 에서 을 때 VCS
시스대부분은 관리하는 정보가 일들의 목록이다. CVS, Subversion, Perforce, Bazaar 등의 시스은 각 일의
변화를 시간순으로 관리하면서 일들의 합을 관리한다(델타 기반 버전관리 시스이라 함).
12
그림 4. 각 파일에 대한 변화를 저장하는 시스템들.
Git은 이런 으로 데이터를 저하지도 하지도 않는다. 대신 Git은 데이터를 일 시스냅샷속으로
하고 크기가 주 작다. Git은 커하거나 프로젝트의 상를 저할 때마다 일이 존재하는 그 순간을 중요하게
. 일이 달라지지 않았으면 Git은 성을 위해서 일을 새로 저하지 않는다. 지 이전 상일에 대한
크만 저한다. Git은 데이터를 스냅샷의 스트림처럼 한다.
그림 5. 시간순으로 프로젝트의 스냅샷을 저장.
이것이 Git이 다른 VCS와 구분되는 이다. 때문에 Git은 다른 시스들이 과거로부터 습해왔던 버전
개념과 다다는 것이고 많은 부분을 새로운 관점에서 바라. Git력한 도를 지원하는 작은 일시스이다.
Git순한 VCS니다. Git 브랜에서 명할 Git 브랜치를 사용하면 게 되는 이이 무엇인지 명한다.
거의 모든 명령을 로컬에서 실행
거의 모든 명령이 로컬 파일과 데이터만 사용하기 때문에 크에 있는 다른 컴퓨터는 요 없다. 대부분의 명령어가
크의 속도에 영CVCS하다면 Git것이다. Git의 이런 특에서 나오는 미칠
속도는 오Git만이 사할 수 있는 전이다. 프로젝트의 모든 히스토리가 로디스크에 있기 때문에 모든 명령이
간에 실된다.
예를 들어 Git은 프로젝트의 히스토리회할 때 서버 없이 회한다. 데이터이스에서 히스토리어서
13
보여 . 깜짝할 사이에 히스토리회할 수 있다. 떤 파일의 재 버전과 한 달 전의 상를 비해보고
을 때도 Git은 그한 달 전의 일과 지금의 일을 로에서 는다. 일을 비하기 위해 모트에 있는 서버에
하고 나서 예전 버전을 가져올 필요가 없다.
오프라인 상이거나 VPN연결하지 못해도 없이 일 할 수 있다. 기나 기등에서 작하고 크에
접속하고 있지 않도 커할 수 있다(로컬 소라는 이 기나는지). 다른 VCS 시스에서는 한 일이다.
Perforce를 예로 들자면 서버에 연결할 수 없을 때 할 수 있는 일이 로 없다. Subversion이나 CVS에서도 마가지다.
오프라인이기 때문에 데이터이스에 접할 수 없어서 일을 편할 수는 있지만, 할 수 없다. 우 사소해 보이지만
실제로 이 상에 부닥쳐보면 느지는 이가 우 크다.
Git의 무결성
Git은 데이터를 저하기 전에 하고 그 으로 데이터를 관리한다. 을 이해하는 Git
없이는 어일이나 디렉토리경할 수 없다. Git에서 사용하는 가적인(Atomic) 데이터 위이자
Git의 기본 철이다. Git 없이는 을 다수 없어서 일의 상도 알 수 없고 심지어 데이터를 어버수도 없다.
GitSHA-1 해시를 사용하여 을 만든다. 만든 40이의 16수 문자열이다. 일의 내용이나
렉토리 구조를 이용하여 한다. SHA-1아래처럼 생.
24b9da6552252987aa493b52f8696cd6d3b00373
Git은 모든 것을 해시로 식별하기 때문에 이런 은 여기저기서 보인다. 실제로 Git일을 이름으로 저하지 않고 해당
일의 해시로 저한다.
Git은 데이터를 추가할 뿐
Git으로 무하든 Git 데이터이스에 데이터가 추가 된다. 돌리거나 데이터를 제할 방법이 없다. 다른 VCS처럼
Git도 커하지 않으면 경사어버수 있다. 하지만, 냅샷을 커하고 나면 데이터를 어버기 어렵다.
Git을 사용하면 프로젝트가 심각하게 가질 정 없이 즐겁게 여러 가지 실을 해 볼 수 있다. 돌리을 보면
Git에서 데이터를 어떻게 저하고 실을 어떻게 복구하는지 알 수 있다.
세 가지 상태
이 부분은 중요하기에 중해서 한다. Git부하기 위해 드시 고 넘어가할 부분이다. Git일을
Committed, Modified, Staged 게 세 가지 상관리한다.
Committed데이터가 로데이터이스에 전하게 저됐다는 것을 의한다.
Modified는 수정한 일을 아직 데이터이스에 커하지 않은 것을 한다.
Staged란 현재 수정한 일을 할 것이라고 시한 상를 의한다.
이 세 가지 상Git 프로젝트의 세 가지 와 연결돼 있다. Git 렉토리, , Staging Area 게 세 가지
계를 이해하고 넘어가자.
14
그림 6. 워킹 트리, Staging Area, Git 디렉토리.
Git 렉토리Git이 프로젝트의 타데이터와 객체 데이터이스를 저하는 한다. Git 렉토리Git
핵심이다. 다른 컴퓨터에 있는 저소를 Clone 할 때 Git 렉토리가 만들어.
는 프로젝트의 특정 버전을 Checkout 한 것이다. Git 렉토리는 지금 작하는 디스크에 있고 그 디렉토리
된 데이터이스에서 일을 가져와를 만든다.
Staging AreaGit 렉토리에 있다. 순한 일이고 일에 대한 정보를 저한다. Git에서는 기용어로는
“Index” 라고 하지만, “Staging Area” 라는 용어를 써도 상없다.
Git으로 하는 일은 기적으로 아래와 같.
1. 에서 일을 수정한다.
2. Staging Area일을 Stage 해서 커할 스냅샷을 만든다. 모든 일을 추가할 수도 있고 선택하여 추가할 수도
있다.
3. Staging Area에 있는 일들을 커해서 Git 렉토리에 영적인 스냅샷으로 저한다.
Git 렉토리에 있는 일들은 Committed 이다. 일을 수정하고 Staging Area에 추가했다면 Staged이다.
Checkout 하고 나서 수정했지만, 아직 Staging Area에 추가하지 않았으면 Modified이다. Git의 기에서 이 상
대해 좀 더 자세히 배운다. 특히 Staging Area를 이용하는 방법부터 예 생하는 방법까지도 명한다.
CLI
Git을 사용하는 방법은 많다. CLI로 사용할 수도 있고 GUI를 사용할 수도 있다. 이 책에서는 Git CLI 사용명한다.
Git모든 을 지원하는 것은 CLI 뿐이다. GUI 프로그의 대부분은 Git 중 일부만 구현하기 때문에 비
순하다. CLI를 사용할 알면 GUI도 사용할 수 있지만 대는 성하지 않는다. GUI를 사용하고 더라도 CLI
으로 치되는 도이기 때문에 CLI으로 명하.
15
서 우MacTerminal이나 WindowsCMDPowershell을 실시키는 방법은 알고 있을 거라고 가정했다.
이 무인지 모르겠다면 일여기서 추고 Terminal이나 Powershell에 대해 알보기 바. 래야
책의 명을 따라수 있다.
Git 설치
Git을 사용하려면 우선 설치해한다. 미 설치했으면 신 버전으로 데이트하는 게 좋다. 키지를 치하거나
도의 인스러로 치할 수 있다. 니면 접 소스코드를 내려받아컴파일할 수도 있다.
이 책은 Git 2.0.0 버전을 기으로 . 대부분의 명령어는 그 이전 버전에서도 동작하지만,
가지 기예 없거나 하게 다를 수 있다. Git의 하위 호환성은 정훌륭하기 때문에 2.0 이후
버전에서는 동작한다.
Linux에 설치
Linux에서 키지로 Git치할 때는 보각 배포판에서 사용하는 키지 관리를 사용하여 치한다. Fedora
(또는 비하게 RPM 반 패키지 시스을 사용하는 RHEL, CentOS)에서는 아래와 같`dnf`를 사용 한다.
$ sudo dnf install git-all
Ubuntu등의 데비계열 배포판에서는 `apt`를 사용한다.
$ sudo apt install git-all
다른 Unix 배포판에 치하려면 http://git-scm.com/download/linux 에서 인하라.
Mac에 설치
MacGit치하는 방법 중에는 Xcode Command Line Tools치하는 방법이 가쉽다. Mavericks
(10.9)부터는 Terminal지 처음으로 'git’을 실하는 것으로 치가 시작된다. 'git’있지 않으면
치하라고 내해.
$ git --version
Git이 시스치되어있지 않은 경우, 치할 수 있도록 시지가 것이다.
좀 더 신 버전이 요하면 바이너리 인스러로 치할 수 있다. macOSGit 인스러는 Git 웹사이트에서 관리하고
있으며 http://git-scm.com/download/mac 에서 내려는다.
16
그림 7. Git macOS 인스톨러.
'GitHub for Mac’치하는 방법도 있다. 이 도에도 CLI 치하는 옵션이 있다. 'GitHub for Mac’
http://mac.github.com에서 내려는다.
Windows에 설치
WindowsGit치하는 방법은 여러 가지다. 공식 배포판은 Git 웹사이트에서 내려을 수 있다. http://git-
scm.com/download/win에 가면 자동으로 다운로드가 시작된다. 이 프로젝트가 'Git for Windows인데, Git 체와
다른 도의 프로젝트다. 자세한 정보는 https://git-for-windows.github.io/에서 인한다.
자동방식Git Chocolatey 키지해 이용해볼 수 있다. 키지는 커뮤니티에 의해 운영되는 프로그
을 알려드.
Windows에서도 Git을 사용하는 또 다른 방법으로 'GitHub Desktop치하는 방법이 있다. 이 인스러는 CLI
GUI를 모두 설치해. 치하면 GitPowershell에서 사용할 수 있다. 정보(Credential) 캐싱CRLF 정까지
된다. 이런 것들은 차차 배우게 될 것인데, Git 사용자라면 쓰게 될 기들이다. 'GitHub DesktopGitHub
Desktop 웹사이트에서 내려는다.
소스코드로 설치하기
장 최신 버전이 요하면 소스코드로 치하는 것이 좋다. 바이너리 인스러는 는다. 최근 Git우 성해서
경이 크지 않지만, 이 난다.
17
Git치하려면 Git이 의존하고 있는 라이autotools, curl, zlib, openssl, expat, libiconv등이 요하다.
예를 들어 `dnf`을 사용하는 Fedora등의 시스이나 `apt-get`이 있는 데비계열 시스이면 아래 명령어 중 하나를
하여 요한 키지를 치할 수 있다.
$ sudo dnf install dh-autoreconf curl-devel expat-devel gettext-devel \
Ê openssl-devel perl-devel zlib-devel
$ sudo apt-get install dh-autoreconf libcurl4-gnutls-dev libexpat1-dev \
Ê gettext libz-dev libssl-dev
문서를 다(doc, html, info) 형식으로 추가하려면 다음의 키지들이 추가로 요하다(주의: CentOSScientific
Linux RHEL 계열 사용자는 EPEL 소를 docbook2X 키지를 다운로드해한다.)
$ sudo dnf install asciidoc xmlto docbook2X
$ sudo apt-get install asciidoc xmlto docbook2x
데비계열 시스이면 install-info 키지도 치해한다.
$ sudo apt-get install install-info
RPM을 사용하는 Fedora나 비한 시스을 사용한다면 getopt 키지도 치해한다(이는 데비계열 시스에는
미 설치되어 있다).
$ sudo dnf install getopt
$ sudo apt-get install getopt
Fedora/RHEL/RHEL 계열 사용자라면 아래 명령도 요하다.
$ sudo ln -s /usr/bin/db2x_docbook2texi /usr/bin/docbook2x-texi
행파일 이름이 달라서 그.
모든 비가 되면, 신 배포 버전을 가져와야 한다. Kernel.org(https://www.kernel.org/pub/software/scm/
git)에서 내려을 수도 있고 GitHub에 있는 (https://github.com/git/git/releases)에서도 을 수도 있다.
GitHub 이지에서 신 버전을 내려는 것이 더 간하지만 kernel.org에는 배포 시그처가 있어서 내려은 것을
검증할 수 있다.
이제, 컴파일하고 치하자.
18
$ tar -zxf git-2.0.0.tar.gz
$ cd git-2.0.0
$ make configure
$ ./configure --prefix=/usr
$ make all doc info
$ sudo make install install-doc install-html install-info
치하고 나면 Git을 사용하여 Git 소스코드를 받아서 수정할 수도 있다.
$ git clone git://git.kernel.org/pub/scm/git/git.git
Git 최초 설정
Git치하고 나면 Git의 사용 환경을 적절하게 정해 주어한다. 환경 정은 한 컴퓨터에서 한 만 하면 된다.
정한 내용은 Git이드해도 유지된다. 제든지 다시 바수 있는 명령어도 있다.
'git config’라는 도정 내용을 인하고 경할 수 있다. Git은 이 정에 따라 동작한다. 이때 사용하는
일은 세 가지나 된다.
1. /etc/gitconfig : 시스의 모든 사용자모든 저소에 적용되는 정이다. git config --system
옵션으로 이 일을 고 쓸 수 있다. (일은 시스체 설일이기 때문에 수정하려면 시스관리
한이 요하다.)
2. ~/.gitconfig, ~/.config/git/config : 특정 사용자(즉 현재 사용자)에게만 적용되는 정이다. git
config --global 옵션으로 이 일을 고 쓸 수 있다. 특정 사용자의 모든 정에 적용된다.
3. .git/config : 일은 Git 렉토리에 있고 특정 저(재 작중인 프로젝트)에만 적용된다.
--local 옵션을 사용하면 이 일을 사용하도록 지정할 수 있다. 하지만 기적으로 이 옵션이 적용되어 있다.
(, 옵션을 적용하려면 Git 소인 디렉토리로 이동 한 후 적용할 수 있다.)
정은 순으로 우시 된다. .git/config /etc/gitconfig 보다 우한다.
Windows에서는 $HOME 렉토리에서 .gitconfig 일을 는다(마도 C:\Users\$USER 렉토리).
Windows에서도 /etc/gitconfig 일은 그 경로에서 는다. 이 경로는 마도 MSys 루트의 상대경로일 ,
MSys 루트는 인스러로 GitWindows치할 때 정된다. 'Git for Windows' 2.x 버전에서는 금 다.
Windows XP 사용자는 C:\Documents and Settings\All Users\Application Data\Git\config
렉토리에서 을 수 있고 Windows Vista 이후 버전 사용자는 C:\ProgramData\Git\config 에서 을 수 있다.
이 시스템 설일의 경로는 git config -f <file> 명령으로 경할 수 있다. 관리한이 요하다.
사용자 정보
Git치하고 나서 가장 먼저 해하는 것은 사용자이름과 이일 주소를 정하는 것이다. Git은 커할 때마다 이
정보를 사용한다. 한 후에는 정보를 경할 수 없다.
19
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
다시 하자면 --global 옵션으로 정하는 것은 만 하면 된다. 해당 시스에서 해당 사용자가 사용할 때는 이
정보를 사용한다. 프로젝트마다 다른 이름과 이일 주소를 사용하고 으면 --global 옵션을 빼고 명령을
한다.
GUI 들은 처음 실할 때 이 정을 는다.
편집기
사용자 정보를 정하고 나면 Git에서 사용할 스트 편기를 고른다. 적으로 Git은 시스의 기기를
사용한다.
하지만, Emacs 은 다른 스트 편기를 사용할 수 있고 아래와 같이 실하면 된다.
$ git config --global core.editor emacs
Windows 사용자라면 다른 스트 편기를 사용할 수 있다. 행파일의 전경로를 정해주면 된다. 행파일의 전
경로는 사용하는 편기에 따라 다.
Windows 환경에서 많이 사용되는 Notepad 기의 경우 주로 32비트 버전을 사용하게 된다. 재 기으로 64비트
버전을 사용하면 동작하지 않는 플러그인이 많다. 32비트 Windows 시스이거나, 64비트 Windows 시스에서
64비트 Notepad치했다면 다음과 정한다.
$ git config --global core.editor "'C:/Program
Files/Notepad++/notepad++.exe' -multiInst -nosession"
64비트 Windows 시스에서 32비트 Notepad++치했다면 `C:\Program Files (x86)`치된다.
$ git config --global core.editor "'C:/Program Files
(x86)/Notepad++/notepad++.exe' -multiInst -nosession"
VimEmacs, Notepad++인기 있는 편기로 개발자들이 사용한다. Mac이나 Linux
Unix 시스, Windows 시스에서 사용 가하다. 여기서 소개하는 편기들이 편해서 다른
기를 사용하고자 한다면 해당 편기를 Git 기로 정하는 방법찾아한다.
자신의 편기를 정하지 않으면 자기 실된 편기에 당할 수 있다. 그땐 당하지
기를 그하면 Git 명령을 소할 수 있다.
20
설정 확인
git config --list 명령을 실하면 정한 모든 것을 보여주어 바로 인할 수 있다.
$ git config --list
user.name=John Doe
user.email=johndoe@example.com
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
...
Git은 키를 여러 (/etc/gitconfig ~/.gitconfig )에서 기 때문에 은 키가 여러 개 있을 수도
있다. 그러면 Git은 나중 을 사용한다.
git config <key> 명령으로 Git이 특정 Key에 대해 어을 사용하는지 인할 수 있다.
$ git config user.name
John Doe
Git정된 을 때 여러 일에서 동일한 키에 대해 다른 정하고 있을 수 있다.
기대한 과 다를 수 있는데 만 보고 쉽게 그 원인을 을 수 없다. 이 때 키에 정된 어디에서
정되었는지 인할 수 있는데 다음과 은 명령으로 어떤 파일로부터 정된 인지를 인할 수
있다.
$ git config --show-origin rerere.autoUpdate
file:/home/johndoe/.gitconfig false
도움말 보기
명령어에 대한 도움요할 때 도움을 보는 방법가지로 동일한 과를 볼 수 있다.
$ git help <verb>
$ man git-<verb>
예를 들어 아래와 같이 실하면 git config 명령에 대한 도움을 볼 수 있다.
$ git help config
도움제 어디서나 볼 수 있다. 오프라인으로도 볼 수 있다. 도움과 이 책으로 부하면 다른 사람의 도움을
21
것이 요하다. Freenode IRC 서버(irc.freenode.net)에 있는 #git 이나 #github 채널찾아가라. 채널에는 보
수백 명의 사람이 접속해 있다. Git에 대해 알고 있다. 이 도와줄 것이다.
Git 명령을 사용하기 위해 우 자세한 도움를 볼 요 없이 각 명령에서 사용할 수 있는 옵션들에 대해서 간
살펴볼수도 있다. -h, --help 옵션을 사용하면 다음과 Git 명령에서 사용할 수 있는 옵션들에 대한 간한 도움
출력한다.
$ git add -h
usage: git add [<options>] [--] <pathspec>...
Ê -n, --dry-run dry run
Ê -v, --verbose be verbose
Ê -i, --interactive interactive picking
Ê -p, --patch select hunks interactively
Ê -e, --edit edit current diff and apply
Ê -f, --force allow adding otherwise ignored files
Ê -u, --update update tracked files
Ê -N, --intent-to-add record only the fact that the path will be added
later
Ê -A, --all add changes from all tracked and untracked files
Ê --ignore-removal ignore paths removed in the working tree (same
as --no-all)
Ê --refresh don't add, only refresh the index
Ê --ignore-errors just skip files which cannot be added because of
errors
Ê --ignore-missing check if - even missing - files are ignored in
dry run
Ê --chmod <(+/-)x> override the executable bit of the listed files
요약
Git이 무엇이고 지금까지 사용해 온 다른 CVCS어떻게 다른지 배. 시스Git치하고 사용자 정보도
정했다. 다음 에서는 Git의 사용을 배운다.
22
Git의 기초
Git을 사용하는 방법을 알고 은데 한 을 시간이 없다면 이터를 한다. Git에서 자주 사용하는
명령어는 모2에 등한다. 2을 다 으면 저소를 만들고 정하는 방법, 일을 추적하거나(Track) 추적을
그만방법, 경 내용을 Stage 하고 커하는 방법을 알게 된다. 일이나 을 무시하도록 Git정하는
방법, 실수를 쉽고 빠르게 만회하는 방법, 프로젝트 히스토리회하고 커을 비하는 방법, 모트 저소에 Push
하고 Pull 하는 방법을 살펴.
Git 저장소 만들기
주로 다음 가지 중 한 가지 방법으로 Git 소를 쓰기 시작한다.
1. 아직 버전관리를 하지 않는 로렉토리 하나를 선택해서 Git 소를 적용하는 방법
2. 다른 어가에서 Git 소를 Clone 하는 방법
떤 방법을 사용하든 로렉토리Git 소가 비되면 이제 가 해볼 수 있다.
기존 디렉토리를 Git 저장소로 만들기
버전관리를 하지 니하는 기존 프로젝트를 Git으로 관리하고 은 경우 우프로젝트의 디렉토리로 이동한다. 이러한
과정을 처음 해보는 것이라면 시스마다 금 다른 을 주의하자.
Linux:
$ cd /home/user/my_project
Mac:
$ cd /Users/user/my_project
Windows:
$ cd /c/user/my_project
아래와 같은 명령을 실한다:
$ git init
이 명령은 .git 이라는 하위 디렉토리를 만든다. .git 렉토리에는 저소에 요한 (Skeleton)이 들어
있다. 이 명령만으로는 아직 프로젝트의 어떤 파일도 관리하지 않는다. (.git 렉토리만들어진 직후에 정히 어
일이 있는지에 대한 내용은 Git의 내부에서 다)
23
Git일을 관리하게 하려면 저소에 일을 추가하고 커한다. git add 명령으로 일을 추가하고 git
commit 명령으로 커한다:
$ git add *.c
$ git add LICENSE
$ git commit -m 'initial project version'
명령어 개로 순간에 Git 소를 만들고 일 버전 관리를 시작했다.
기존 저장소를 Clone 하기
다른 프로젝트에 참여하려거나(Contribute) Git 소를 사하고 을 때 git clone 명령을 사용한다.
Subversion VCS한 사용자에게는 "checkout" 니라 "clone" 이라는 이 도드라보일 것이다. Git
Subversion과 다른 가장 큰 차은 서버에 있는 거의 모든 데이터를 사한다는 것이다. git clone 을 실하면
프로젝트 히스토리를 전부 받아온다. 실제로 서버의 디스크가 라이트 저소 중에서 무거나 하나
다가 복구하면 된다(서버에만 적용했던 정은 복구하지 못하지만 모든 데이터는 복구된다 - 서버에 Git
치하기에서 좀 더 자세히 다).
git clone <url> 명령으로 저소를 Clone 한다. libgit2 라이소스코드를 Clone 하려면 아래
한다.
$ git clone https://github.com/libgit2/libgit2
이 명령은 “libgit2” 라는 디렉토리를 만들고 그 .git 렉토리를 만든다. 고 저소의 데이터를 모져와
자동으로 가장 최신 버전을 Checkout 해 놓는다. libgit2 렉토리로 이동하면 Checkout으로 생성한 일을 볼 수
있고 당하고자 하는 일을 시작할 수 있다.
아래은 명령을 사용하여 저소를 Clone 하면 `libgit2`니라 다른 디렉토리 이름으로 Clone 할 수 있다.
$ git clone https://github.com/libgit2/libgit2 mylibgit
렉토리 이름이 mylibgit 이라는 것만 빼면 이 명령의 명령의 과는 .
Git은 다한 프로토콜을 지원한다. 이제까지는 https:// 프로토콜을 사용했지만 git:// 를 사용할 수도 있고
user@server:path/to/repo.git 처럼 SSH 프로토콜을 사용할 수도 있다. 자세한 내용은 서버에 Git
치하기에서 다루며 각 프로토콜장단점Git 소에 접하는 방법명한다.
수정하고 저장소에 저장하기
만질 수 있는 Git 소를 하나 만들었고 렉토리Checkout도 했다. 이제는 일을 수정하고 일의 스냅샷
해 보자. 일을 수정하다가 저하고 으면 스냅샷을 커한다.
렉토리의 모든 일은 크게 Tracked(관리대상)Untracked(관리대상이 )로 나. Tracked 일은
냅샷에 포함있던 일이다. Tracked 일은 또 Unmodified(수정하지 않음)Modified(수정함)
24
Staged(으로 저소에 기록할) 중 하나이다. 하자면 Git이 알고 있는 일이라는 것이다.
고 나일은 모Untracked 일이다. Untracked 일은 렉토리에 있는 일 중 스냅샷에도 Staging
Area에도 포함되지 않은 일이다. 처음 저소를 Clone 하면 모든 일은 Tracked이면서 Unmodified 이다.
일을 Checkout 하고 나서 무것도 수정하지 않았기 때문에 그.
마지이후 아직 아무것도 수정하지 않은 상에서 어떤 파일을 수정하면 Git은 그 일을 Modified
한다. 실제로 커을 하기 위해서는 이 수정한 일을 Staged 로 만들고, Staged 일을 커한다. 이런
라이프사이을 계속 반복한다.
그림 8. 파일의 라이프사이클.
파일의 상태 확인하기
일의 상인하려면 보git status 명령을 사용한다. Clone 한 후에 바로 이 명령을 실하면 아래
시지를 볼 수 있다.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
위의 내용은 일을 하나도 수정하지 않았다는 것을 . Tracked 일은 하나도 수정되지 않았다는 의.
Untracked 일은 아직 없어서 목록에 나타나지 않는다. 재 작중인 브랜치를 알려주며 서버의
브랜치로부터 진행된 작이 없는 것을 나타. 본 브랜치가 master이기 때문에 브랜치 이름이 “master”
나온다. 브랜관련 내용은 차차 가자. Git 브랜 에서 브랜Refs에 대해 자세히 다.
프로젝트에 README 일을 만들어보자. README 일은 새로 만든 일이기 때문에 git status 를 실하면
'Untracked files에 들어 있다:
25
$ echo 'My Project' > README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
Ê (use "git add <file>..." to include in what will be committed)
Ê README
nothing added to commit but untracked files present (use "git add" to
track)
README 일은 “Untracked files부분에 속해 있는데 이것은 README 일이 Untracked 라는 것을 한다.
GitUntracked 일을 아직 냅샷()어지지 않은 일이라고 . 일이 Tracked 가 되기 전까지는
Git은 절대 그 일을 커하지 않는다. 서 일하면서 생성하는 바이너리 파은 것을 커하는 실수는 하지 않게
된다. README 일을 추가해서 Tracked 로 만들어 보자.
파일을 새로 추적하기
git add 명령으로 일을 새로 추적할 수 있다. 아래 명령을 실하면 GitREADME 일을 추적한다.
$ git add README
git status 명령을 다시 실하면 README 일이 Tracked 이면서 커에 추가될 Staged 라는 것을 인할
수 있다.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê new file: README
“Changes to be committed” 에 들어 있는 일은 Staged 라는 것을 의한다. 하면 git add 를 실
일이 커되어 저소 히스토리는다. 에서 git init 명령을 실한 후, git add (files) 명령을
했던 걸 기할 것이다. 이 명령을 해 디렉토리에 있는 일을 추적하고 관리하도록 한다. git add 명령은
또는 디렉토리의 경로를 아규먼트로 는다. 렉토리아래에 있는 모든 일들까지 재적으로 추가한다.
Modified 상태의 파일을 Stage 하기
Tracked 일을 수정하는 을 알보자. CONTRIBUTING.md 라는 일을 수정하고 나서 git status
명령을 다시 실하면 과는 아래와 같.
26
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê new file: README
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: CONTRIBUTING.md
CONTRIBUTING.md 일은 “Changes not staged for commit” 에 있다. 이것은 수정한 일이 Tracked
이지만 아직 Staged 니라는 것이다. Staged 로 만들려면 git add 명령을 실한다. git add
명령은 일을 새로 추적할 때도 사용하고 수정한 일을 Staged 로 만들 때도 사용한다. Merge 할 때 난 상
일을 Resolve 로 만들때도 사용한다. add의 의는 프로젝트에 일을 추가한다기 보다는 다음 커에 추가한다고
받아들이는게 좋다. git add 명령을 실하여 CONTRIBUTING.md 일을 Staged 로 만들고 git status
명령으로 과를 인해보자.
$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê new file: README
Ê modified: CONTRIBUTING.md
두 파일 모Staged 로 다음 커에 포함된다. 하지만 아직 더 수정해한다는 것을 알게 되어 바로 커하지
못하는 상이 되었다고 생각해보자. 이 상에서 CONTRIBUTING.md 일을 열고 수정한다. 이제 커비가 다
됐다고 생각할 지만, Git은 그지 않다. git status 명령으로 일의 상를 다시 인해보자.
27
$ vim CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê new file: README
Ê modified: CONTRIBUTING.md
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: CONTRIBUTING.md
! CONTRIBUTING.md Staged 이면서 동시에 Unstaged 로 나온다. 어떻게 이런 일이 가할까? git
add 명령을 실하면 Git일을 바로 Staged 로 만든다. 지금 이 시에서 커을 하면 git commit 명령을
하는 시의 버전이 커되는 것이 니라 마지으로 git add 명령을 실했을 때의 버전이 커된다. 그러니까
git add 명령을 실한 후에 또 일을 수정하면 git add 명령을 다시 실해서 신 버전을 Staged 로 만들어
한다.
$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê new file: README
Ê modified: CONTRIBUTING.md
파일 상태를 짤막하게 확인하기
git status 명령으로 인할 수 있는 내용이 좀 많보일 수 있다. 사실 그. 좀 더 간하게 경 내용을 보여주는
옵션이 있다. git status -s 또는 git status --short 처럼 옵션을 주면 경한 상하게
보여.
28
$ git status -s
ÊM README
MM Rakefile
A lib/git.rb
M lib/simplegit.rb
?? LICENSE.txt
아직 추적하지 않는 새 에는 ?? 시가 는다. Staged 로 추가한 일 중 새로 생성한 에는 A 시가,
수정한 에는 M 시가 는다. 위 명령의 과에서 상정보 럼에는 가지 정보를 보여. 왼쪽에는 Staging
Area에서의 상, 오른에는 Working Tree에서의 상시한다. README 은 경우 내용을 경했지만
아직 Staged 로 추가하지는 않았다. lib/simplegit.rb 일은 내용을 경하고 Staged 로 추가까지 한
이다. 과에서 을 비해보자. Rakefile 경하고 Staged 로 추가한 후 또 내용을 경해서
Staged 이면서 Unstaged 일이다.
파일 무시하기
떤 파일은 Git관리요가 없다. 로그 일이나 드 시스이 자동으로 생성한 일이 그. 그런 일을
무시하려면 .gitignore 일을 만들고 그 에 무시할 을 적는다. 아래.gitignore 일의 예이다.
$ cat .gitignore
*.[oa]
*~
번째 라인은 확장자가 “.o“.a” 일을 Git이 무시하라는 것이고 둘라인은 ~ 나는 모든 일을
무시하라는 것이다. 대부분의 스트 편기에서 일로 사용하는 일 이름이기 때문이다. “.o“.a” 는 각각
드 시스이 만들어내는 오젝트와 아브 파일이고 ~ 나는 일은 EmacsVI 스트 편기가 시로
만들어내는 일이다. log, tmp, pid 은 디렉토리, 자동으로 생성하는 문서 은 것들도 추가할 수 있다.
.gitignore 일은 보처음에 만들어 는 것이 편하다. Git 소에 커하고 지 않은 일을 실수로
하는 일을 지할 수 있다.
.gitignore 일에 입력하는 아래 규칙을 따른다.
무것도 없는 라인이나, `#`로 시작하는 라인은 무시한다.
표준 Glob 을 사용한다. 이는 프로젝트 전에 적용된다.
(/)로 시작하면 하위 디렉토리에 적용되지(Recursivity) 않는다.
렉토리(/)에 사용하는 것으로 표현한다.
(!)로 시작하는 일은 무시하지 않는다.
Glob 은 정규표현식순하게 만든 것으로 생각하면 되고 보에서 많이 사용한다. 스터스크(*)는 문자가
하나도 없거나 하나 이상을 의하고, [abc] 는 중에 있는 문자 중 하나를 의한다(그러니까 이 경우에는 a, b,
c). (?)는 문자 하나를 하고, [0-9] 처럼 중캐릭터 사이에 하이픈(-)을 사용하면 그 캐릭터 사이에
있는 문자 하나를 한다. 스터스크 2개를 사용하여 디렉토리 안의 디렉토리 까지 지정할 수 있다. a/**/z
a/z, a/b/z, a/b/c/z 렉토리에 사용할 수 있다.
29
아래.gitignore 일의 예이다.
# 확장자가 .a 무시
*.a
# 라인에서 확장자가 .a 일은 무시하게 했지만 lib.a 무시하지 않음
!lib.a
# 렉토리 있는 TODO일은 무시하고 subdir/TODO처럼 하위디렉토리 있는 일은
무시하지 않음
/TODO
# build/ 렉토리 있는 모든 일은 무시
build/
# doc/notes.txt 일은 무시하고 doc/server/arch.txt 일은 무시하지 않음
doc/*.txt
# doc 렉토리 아래 모든 .pdf 일을 무시
doc/**/*.pdf
GitHub은 다한 프로젝트에서 자주 사용하는 .gitignore 예제를 관리하고 있다. 내용을
을지 막막하다면 https://github.com/github/gitignore 사이트에서 적당한 예제를 을 수 있다.
.gitignore` 사용하는 방식 하나의 `.gitignore 일을 상위 디렉토리
하나 고 모든 하위 디렉토리에까지 적용시키는 방식이다. 물론 .gitignore 일을 하나만
것이 니라 하위 디렉토리에도 추가로 둘 수도 있다. .gitignore 정책은 .gitignore
일이 위치한 디렉토리와 그 하위 디렉토리에 적용된다. (스 커소스 저소에는
.gitignore 일이 206개나 있음)
다수의 .gitignore 일을 고 정책을 적용하는 부분은 이 책에서 다루는 위를 어난다.
자세한 내용은 `man gitignore`에서 인할 수 있다.
StagedUnstaged 상태의 변경 내용을 보기
순히 일이 경됐다는 사실이 니라 어내용이 경됐는지 살펴보려면 git status 명령이 니라 git diff
명령을 사용해한다. '수정했지만, 아직 Staged 일이 ?''떤 파일이 Staged 인지?'
금하기 때문에 git status 명령으로도 분하다. 더 자세하게 볼 때는 git diff 명령을 사용하는데 Patch처럼
라인을 추가했고 제했는지가 금할 때 사용한다. git diff 는 나중에 더 자세히 다.
README 일을 수정해서 Staged 로 만들고 CONTRIBUTING.md 일은 그수정만 해. 이 상에서 git
status 명령을 실하면 아래와 같시지를 볼 수 있다.
30
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê modified: README
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: CONTRIBUTING.md
git diff 명령을 실하면 수정했지만 아직 staged 일을 비해 볼 수 있다.
$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
ÊPlease include a nice description of your changes when you submit your
PR;
Êif we have to read the whole diff to figure out why you're contributing
Êin the first place, you're less likely to get feedback and have your
change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your
patch is
+longer than a dozen lines.
ÊIf you are starting to work on a particular area, feel free to submit a
PR
Êthat highlights your work in progress (and note in the PR title that it's
이 명령은 렉토리에 있는 것과 Staging Area에 있는 것을 비한다. 서 수정하고 아직 Stage 하지 않은 것을
보여.
하려고 Staging Area일의 경 부분을 보고 으면 git diff --staged 옵션을 사용한다.
명령은 저소에 커한 것과 Staging Area에 있는 것을 비한다.
31
$ git diff --staged
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+My Project
꼭 잊말아야 할 것이 있는데 git diff 명령은 마지으로 커한 후에 수정한 것들 전부를 보여주지 않는다. git
diff Unstaged 인 것들만 보여. 수정한 일을 모Staging Area었다면 git diff 명령은
무것도 출력하지 않는다.
CONTRIBUTING.md 일을 Stage 한 후에 다시 수정해도 git diff 명령을 사용할 수 있다. 이때는 Staged
것과 Unstaged 인 것을 비한다.
$ git add CONTRIBUTING.md
$ echo '# test line' >> CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê modified: CONTRIBUTING.md
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: CONTRIBUTING.md
git diff 명령으로 Unstaged 경 부분을 인할 수 있다.
32
$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 643e24f..87f08c8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -119,3 +119,4 @@ at the
Ê## Starter Projects
ÊSee our [projects
list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).
+# test line
Staged 일은 git diff --cached 옵션으로 인한다. --staged --cached 옵션이다.
$ git diff --cached
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
ÊPlease include a nice description of your changes when you submit your
PR;
Êif we have to read the whole diff to figure out why you're contributing
Êin the first place, you're less likely to get feedback and have your
change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your
patch is
+longer than a dozen lines.
ÊIf you are starting to work on a particular area, feel free to submit a
PR
Êthat highlights your work in progress (and note in the PR title that it's
외부 도구로 비교하기
이 책에서는 계속 git diff 명령으로 여기저기서 써 는다. 쓰거나 과를 게 보여주는
Diff 가 있으면 사용할 수 있다. git diff 대신 git difftool 명령을 사용해서 emerge,
vimdiff 은 도로 비할 수 있다. 상용 제도 사용할 수 있다. git difftool --tool-help
라는 명령은 사용가한 도를 보여.
변경사항 커밋하기
수정한 것을 커하기 위해 Staging Area일을 정했다. Unstaged 일은 커되지 않는다는 것을
한다. Git은 생성하거나 수정하고 나서 git add 명령으로 추가하지 않은 일은 커하지 않는다. 일은
여전히 Modified 남아 있다. 하기 전에 git status 명령으로 모든 것이 Staged 인지 인할 수 있다.
33
그 후에 git commit 을 실하여 커한다.
$ git commit
Git 정에 지정된 편기가 실되고, 아래와 같스트가 자동으로 포함된다 (아래 예제는 Vim 기의 면이다.
기는 EDITOR 환경 수에 등록된 편기이고 보Vim이나 Emacs을 사용한다. 시작하기 에서
명했git config --global core.editor 명령으로 어기를 사용할지 정할 수 있다).
기는 아래와 같은 내용을 시한다(아래 예제는 Vim ).
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
# new file: README
# modified: CONTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C
자동으로 생성되는 커밋 메시지의 라인은 비어 있고 둘라인부터 git status 명령의 과가 워진.
내용을 쉽게 기할 수 있도록 이 시지를 포함할 수도 있고 시지를 전부 지우고 새로 작성할 수 있다 (
수정했는지도 보여수 있는데, git commit -v 옵션을 추가하면 편기에 diff 시지도 추가된다). 내용을
하고 편기를 하면 Git은 입력된 내용(#로 시작하는 내용을 제외한)으로 새 커을 하나 성한다.
시지를 인라인으로 부할 수도 있다. commit 명령을 실할 때 아래와 같-m 옵션을 사용한다.
$ git commit -m "Story 182: Fix benchmarks for speed"
[master 463dc4f] Story 182: Fix benchmarks for speed
Ê2 files changed, 2 insertions(+)
Êcreate mode 100644 README
번째 을 작성해보았다. commit 명령은 가지 정보를 출력하는데 위 예제는 (master) 브랜치에 커했고
(463dc4f)이라고 알려. 고 수정한 일이 개이고 제됐거나 추가된 라인이 라인인지 알려.
GitStaging Area에 속한 스냅샷을 커한다는 것을 기한다. 수정은 했지만, 아직 Staging Area지 않은
것은 다음에 커할 수 있다. 할 때마다 프로젝트의 스냅샷을 기록하기 때문에 나중에 스냅샷하거나 예전
냅샷으로 되돌릴 수 있다.
34
Staging Area 생략하기
Staging Area는 커일을 정한다는 에서 우 유용하지만 복잡하기만 하고 요하지 않은 때도 있다. 주 쉽게
Staging Area를 생할 수 있다. git commit 명령을 실할 때 -a 옵션을 추가하면 GitTracked 일을
자동으로 Staging Area는다. git add 명령을 실하는 수고를 수 있다.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: CONTRIBUTING.md
no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a -m 'added new benchmarks'
[master 83e38c7] added new benchmarks
Ê1 file changed, 5 insertions(+), 0 deletions(-)
이 예제에서는 커하기 전에 git add 명령으로 CONTRIBUTING.md 일을 추가하지 않았다는 보자. -a
옵션을 사용하면 모든 일이 자동으로 추가된다. 옵션하지만 주의 게 사용해한다. 생각 없이 이 옵션
사용하다 보면 추가하지 말아야 경사도 추가될 수 있기 때문이다.
파일 삭제하기
Git에서 일을 제거하려면 git rm 명령으로 Tracked 일을 제한 후에(하게는 Staging Area에서
제하는 것) 한다. 이 명령은 렉토리에 있는 일도 제하기 때문에 실제로 일도 지워진.
Git 명령을 사용하지 않고 순히 에서 일을 제하고 git status 명령으로 상인하면 Git
“Changes not staged for commit” (, Unstaged )라고 시해.
35
$ rm PROJECTS.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
Ê (use "git add/rm <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê deleted: PROJECTS.md
no changes added to commit (use "git add" and/or "git commit -a")
git rm 명령을 실하면 제한 일은 Staged 가 된다.
$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê deleted: PROJECTS.md
하면 일은 제되고 Git은 이 일을 더는 추적하지 않는다. 미 파일을 수정했거나 Staging Area(- Git
Index라고도 부른다) 추가했다면 -f 옵션을 주어 제로 제해한다. 은 실수로 데이터를 제하지 못하도록
하는 치다. 하지 않고 수정한 데이터는 Git으로 복구할 수 없기 때문이다.
Staging Area에서만 제거하고 렉토리에 있는 일은 지우지 않고 둘 수 있다. 다시 해서 하드디스크에
있는 일은 그대로 Git만 추적하지 않게 한다. 이것은 .gitignore 일에 추가하는 것을 빼었거나 대용로그
일이나 컴파일된 일인 .a 은 것을 실수로 추가했을 때 . --cached 옵션을 사용하여 명령을 실한다.
$ git rm --cached README
여러 개의 일이나 디렉토리를 한꺼번제할 수도 있다. 아래와 같git rm 명령에 file-glob 을 사용한다.
$ git rm log/\*.log
* \ 을 사용한 것을 기하자. 일명 확장 에만 있는 것이 니라 Git 에도 있기 때문에 요하다.
명령은 log/ 렉토리에 있는 .log 일을 모제한다. 아래의 예제처럼 할 수도 있다.
36
$ git rm \*~
이 명령은 ~ 나는 일을 모제한다.
파일 이름 변경하기
Git은 다른 VCS 시스과는 달리 파일 이름의 경이나 일의 이동을 명시적으로 관리하지 않는다. 다시 해서
이름이 경됐다는 도의 정보를 저하지 않는다. Git똑똑해서 일 이름이 경되었다는 것을 추적하지 않
방법이 있다. 일의 이름이 경된 것을 Git이 어떻게 알내는지 살펴보자.
하고 Gitmv 명령이 있는 게 좀 이상하지만, 아래와 같일 이름을 경할 수 있다.
$ git mv file_from file_to
동작한다. 이 명령을 실하고 Git의 상인해보면 Git은 이름이 바뀐 사실을 알고 있다.
$ git mv README.md README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê renamed: README.md -> README
사실 git mv 명령은 아래 명령어를 수한 것과 똑같.
$ mv README.md README
$ git rm README.md
$ git add README
git mv 명령은 일단축 명령어이다. 이 명령으로 일 이름을 바도 되고 mv 명령으로 일 이름을 접 바
된다. git mv 명령은 편하게 명령을 세 해주는 것 뿐이다. 로 이름을 바도 상없다. 중요한
것은 이름을 경하고 나서 rm/add 명령을 실한다는 것 뿐이다.
커밋 히스토리 조회하기
새로 저소를 만들어서 몇 번 을 했을 수도 있고, 히스토리가 있는 저소를 Clone 했을 수도 있다. 든 가
소의 히스토리를 보고 을 때가 있다. Git에는 히스토리회하는 명령어인 git log 가 있다.
이 예제에서는 “simplegit” 이라는 순한 프로젝트를 사용한다. 아래와 같이 이 프로젝트를 Clone 한다.
37
$ git clone https://github.com/schacon/simplegit-progit
이 프로젝트 디렉토리에서 git log 명령을 실하면 아래와 같이 출력된다.
$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
Ê changed the version number
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 16:40:33 2008 -0700
Ê removed unnecessary test
commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 10:31:28 2008 -0700
Ê first commit
아규먼트 없이 git log 명령을 실하면 저소의 커히스토리를 시간순으로 보여. , 장 최근
이 가장 먼저 나온다. 고 이어서 각 커SHA-1 , 저자 이름, 저자 이, , 밋 메시지를
보여.
원하는 히스토리할 수 있도록 git log 명령은 우 다옵션을 지원한다. 여기에서는 자주 사용하는 옵션
명한다.
여러 옵션 -p, --patch 히 유용한 옵션이다. -p 는 각 커diff 과를 보여. 다른 유용한 옵션으로 `-
2`가 있는데 최근 두 개의 과만 보여주는 옵션이다:
38
$ git log -p -2
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
Ê changed the version number
diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
Êspec = Gem::Specification.new do |s|
Ê s.platform = Gem::Platform::RUBY
Ê s.name = "simplegit"
- s.version = "0.1.0"
+ s.version = "0.1.1"
Ê s.author = "Scott Chacon"
Ê s.email = "schacon@gee-mail.com"
Ê s.summary = "A simple gem for using Git in Ruby code."
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 16:40:33 2008 -0700
Ê removed unnecessary test
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index a0a60ae..47c6340 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -18,8 +18,3 @@ class SimpleGit
Ê end
Êend
-
-if $0 == __FILE__
- git = SimpleGit.new
- puts git.show
-end
옵션diff를 실한 것과 과를 출력하기 때문에 동가 무엇을 커했는지 하고 리 조회하는데
유용하다. git log 명령에는 히스토리계를 보여주는 옵션도 있다. --stat 옵션으로 각 커계 정보를
회할 수 있다.
39
$ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
Ê changed the version number
ÊRakefile | 2 +-
Ê1 file changed, 1 insertion(+), 1 deletion(-)
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 16:40:33 2008 -0700
Ê removed unnecessary test
Êlib/simplegit.rb | 5 -----
Ê1 file changed, 5 deletions(-)
commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 10:31:28 2008 -0700
Ê first commit
ÊREADME | 6 ++++++
ÊRakefile | 23 +++++++++++++++++++++++
Êlib/simplegit.rb | 25 +++++++++++++++++++++++++
Ê3 files changed, 54 insertions(+)
과에서 --stat 옵션은 어떤 파일이 수정됐는지, 마나 많은 일이 경됐는지, 마나 많은 라인을 추가하거나
제했는지 보여. 정보는 가뒤쪽에 보여.
다른 또 유용한 옵션--pretty 옵션이다. 옵션해 히스토리 내용을 보여때 기본 형식 이외에 여러 가지 중에
하나를 선택할 수 있다. 선택할 수 있는 옵션이 있다. oneline 옵션은 각 커을 한 라인으로 보여.
옵션은 많은 커을 한 회할 때 유용하다. 추가로 short, full, fuller 옵션도 있는데 이것은 정보를
해서 보여.
$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit
옵션format 옵션이다. 나만의 포으로 과를 출력하고 을 때 사용한다. 특히 과를 다른
프로그으로 하고자 할 때 유용하다. 옵션을 사용하면 포을 정하게 일치시수 있기 때문에 Git을 새
버전으로 바과 포이 바지 않는다.
40
$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : changed the version number
085bb3b - Scott Chacon, 6 years ago : removed unnecessary test
a11bef0 - Scott Chacon, 6 years ago : first commit
git log --pretty=format 에 쓸 가지 유용한 옵션` 에서 사용하는 유용한 옵션.
1. git log --pretty=format 에 쓸 몇가지 유용한 옵션`
옵션 설명
%H
해시
%h
이 커해시
%T
해시
%t
이 트해시
%P
부모 해시
%p
이 부모 해시
%an
저자 이름
%ae
저자
%ad
저자 시각 (형식–-date=옵션 참고)
%ar
저자 상대적 시각
%cn
터 이름
%ce
%cd
터 시각
%cr
터 상대적 시각
%s
저자(Author) 커미터(Committer) 분하는 것이 금 이상해 보일 수 있다. 저자는 원을 수
원작자이고 커터는 마지으로 이 작을 적용한(소에 포함시) 사람이다. 당신이 어프로젝트에 치를
고 그 프로젝트의 당자가 치를 적용했다면 명의 정보를 모요가 있다. 서 이 경우 당신이 저자고 그
당자가 커터다. 환경에서의 Git 에서 이 주제에 대해 자세히 다것이다.
oneline 옵션format 옵션--graph 옵션과 함사용할 때 더 난다. 이 명령은 브랜와 머지 히스토리
보여주는 스키 그프를 출력한다.
41
$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
* 5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
* 11d191e Merge branch 'defunkt' into local
다음 에서 살펴볼 브랜치나 Merge 과의 히스토리를 이런 으로 살펴보면 훨씬 .
git log 명령의 기적인 옵션과 출력형식관련옵션을 살펴보았다. git log 명령은 서 살펴것보다 더
많은 옵션을 지원한다. git log 주요 옵션 는 지금 명한 것과 함유용하게 사용할 수 있는 옵션이다. 옵션으로
어떻게 log 명령을 제어할 수 있는지 보여.
2. git log 주요 옵션
옵션 설명
-p
각 커에 적용된 치를 보여.
--stat
각 커에서 수정된 일의 계정보를 보여.
--shortstat
--stat 명령의 과 중에서 수정한 , 추가된 라인, 제된 라인만 보여.
--name-only
정보중에서 수정된 일의 목록만 보여.
--name-status
수정된 일의 목록을 보여뿐만 니라 일을 추가한 것인지, 수정한 것인지, 제한
것인지도 보여.
--abbrev-commit
40SHA-1 을 전부 보여주는 것이 니라 처음 자만 보여.
--relative-date
한 시간을 보여주는 것이 니라 “2 weeks ago처럼 상대적인 형식으로 보여.
--graph
브랜와 머지 히스토리 정보까지 스키 그프로 보여.
--pretty
지정한 형식으로 보여. 옵션에는 oneline, short, full, fuller, format이 있다. format
원하는 형식으로 출력하고자 할 때 사용한다.
--oneline
--pretty=oneline --abbrev-commit 옵션을 함사용한 것과 .
조회 제한조건
출력 형식관련옵션을 살펴지만 git log 명령은 위를 제한하는 옵션들도 있다. 히스토리 전부가 니라
부분만 회한다. 미 최근 두 개만 회하는 -2 옵션은 살펴. 실제 사용`-<n>`이고 n최근 n개의 커
한다. 사실 이 옵션을 자주 쓰않는다. Git은 기적으로 출력을 pager의 프로그을 거서 내보내로 한
이지보여.
--since --until 은 시간을 기으로 회하는 옵션우 유용하다. 지난 2주 동만들어들만
회하는 명령은 아래와 같.
42
$ git log --since=2.weeks
옵션은 다형식을 지원한다."2008-01-15" 이 정도 사용할 수 있고 "2 years 1 day 3
minutes ago" 이 상대적인 기간을 사용할 수도 있다.
또 다른 기도 있다. --author 옵션으로 저자를 지정하여 할 수도 있고 --grep 옵션으로 커밋 메시지에서
드를 할 수도 있다
--author` `--grep 옵션을 함사용하여 모하는 커으려면 --all-match
옵션드시 함사용해한다.
유용한 옵션으로 -S 가 있는데 이 옵션은 코드에서 추가되거나 제거된 내용 중에 특정 스트가 포함되어 있는지를
한다. 예를 들어 어함수가 추가되거나 제거된 커만을 찾아보려면 아래와 같은 명령을 사용한다.
$ git log -S function_name
마지으로 일 경로로 하는 옵션이 있는데 이것도 정유용하다. 렉토리일 이름을 사용하여 그 일이
경된 log과를 할 수 있다. 옵션-- 경로 이름을 사용하는데 명령어 부분에 (- git
logpath1 path2).
git log 위를 제한하는 옵션 위를 제한하는 옵션들이다.
3. git log 조회 범위를 제한하는 옵션
옵션 설명
-(n)
최근 n 개의 커회한다.
--since, --after 명시한 이후의 커한다.
--until, --before 명시한 이전의 커회한다.
--author
입력한 저자의 커만 보여.
--committer
입력한 커터의 커만 보여.
--grep
밋 메시지 스트를 한다.
-S
밋 변(추가/) 내용 스트를 한다.
이제 살펴볼 예제는 Merge 을 제외한 순수한 커인해보는 명령이다. Junio Hamano200810Git
소스코드 저소에서 스트 일을 수정한 커들이다.
43
$ git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \
Ê --before="2008-11-01" --no-merges -- t/
5610e3b - Fix testcase failure when extended attributes are in use
acd3b9e - Enhance hold_lock_file_for_{update,append}() API
f563754 - demonstrate breakage of detached checkout with symbolic link
HEAD
d1a43f2 - reset --hard/read-tree --reset -u: remove unmerged new paths
51a94af - Fix "checkout --track -b newbranch" on detached HEAD
b0ad11e - pull: allow "git pull origin $something:$current_branch" into an
unborn branch
4만여 개의 커히스토리에서 이 명령의 색 조에 만하는 것은 6개였다.
머지 커밋 표시하지 않기
소를 사용하는 크플로우에 따라 지 커지하는 비중이 수도 있다. --no-merges
옵션을 사용하면 색 결과에서 지 커시하지 않도록 할 수 있다.
되돌리기
일을 하다보면 모든 계에서 어것은 되돌리(Undo) 을 때가 있다. 에는 우가 한 일을 되돌리방법
살펴. 돌리복구할 수 없기에 주의해한다. Git을 사용하면 우가 저지른 실수는 대부분 복구할 수 있지만
돌린 것은 복구할 수 없다.
종종 완한 커을 수정해할 때가 있다. 무 일했거나 어떤 파일을 빼었을 때 그고 커밋 메시지를
적었을 때 한다. 다시 커하고 으면 일 수정 작을 하고 Staging Area에 추가한 다음 --amend 옵션을 사용하여
을 재작성 할 수 있다.
$ git commit --amend
이 명령은 Staging Area를 사용하여 커한다. 마지으로 커하고 나서 수정한 것이 없다면(하자마자 바로 이
명령을 실하는 경우) 금 전에 한 커과 모든 것이 . 이때는 커밋 메시지만 수정한다.
기가 실되면 이전 커밋 메시지가 자동으로 포함된다. 시지를 수정하지 않고 그대로 커해도 기존의 커
.
을 했는데 Stage 하는 것을 깜빡하고 린 파일이 있으면 아래와 같이 고수 있다.
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
여기서 실한 명령어 3개는 모한 개로 기록된다. 두 번째 번째 .
44
--amend 옵션으로 커을 고치는 작, 추가로 작한 일이 작다고 하더라도 이전의
전히 새로 고서 새 커으로 경하는 것을 의한다. 이전의 커은 일어나지 않은 일이
되는 것이고 당히 히스토리에도 지 않는다.
--amend 옵션으로 커을 고치는 작이 주는 장점은 마지에서 주 살빠뜨린
것을 거나 경하는 것을 새 커으로 분하지 않고 하나의 커에서 처하는 것이다. “, 빠진
었음”, “이전 커에서 오타 살등의 커을 만들지 않다는 이다.
파일 상태를 Unstage로 변경하기
다음은 Staging Area와 워렉토리 사이를 넘나드는 방법명한다. 의 상인할 때마다 경된 상
돌리방법을 알려주기 때문에 우 편하다. 예를 들어 일을 개 수정하고서 따로따로 커하려고 했지만, 실수로
git add * 라고 실해 버렸다. 두 파일 모Staging Area에 들어 있다. 이제 둘 중 하나를 어떻게 ? git
status 명령으로 인해보자.
$ git add *
$ git status
On branch master
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê renamed: README.md -> README
Ê modified: CONTRIBUTING.md
Changes to be commited git reset HEAD <file>… 시지가 보인다. 이 명령으로 Unstaged
경할 수 있다. CONTRIBUTING.md 일을 Unstaged 경해보자.
$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê renamed: README.md -> README
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: CONTRIBUTING.md
명령어가 게 느질 수도 있지만 동작한다. CONTRIBUTING.md 일은 Unstaged 가 됐다.
45
git reset 명령은 우 위하다. --hard 옵션과 함사용하면 더하다. 하지만 위에서
처럼 옵션 없이 사용하면 렉토리일은 지 않는다.
지금까지 살펴내용이 git reset 명령에 대해 알아야 할 대부분의 내용이다. reset 명령이 정히는 어떻게
동작하는지, 어떻게 전문적으로 활용하는지는 Reset 히 알고 가기 부분에서 자세히 살펴보기로 한다.
Modified 파일 되돌리기
어떻게 해CONTRIBUTING.md 일을 수정하고 나서 다시 되돌릴 수 있을까? 그러니까 최근 된 버전으로(니면
처음 Clone 했을 때처럼 렉토리에 처음 Checkout 한 그 내용으로) 돌리방법이 무? git status
명령이 절하게 알려. 바로 위에 있는 예제에서 Unstaged 부분을 보자.
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: CONTRIBUTING.md
위의 시지는 수정한 일을 되돌리방법하게 알려. 알려주는 대로 한 해보자.
$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê renamed: README.md -> README
정상적으로 원된 것을 알 수 있다.
git checkout[file] 명령은 한 명령이라는 것을 알아야 한다. 래 파일로
때문에 수정한 내용은 전부 사라. 수정한 내용이 마음에 들지 않을 때만 사용하자.
경한 내용을 쉽게 버수는 없고 하지만 당은 되만 하는 상이라면 StashBranch를 사용하자. Git 브랜
에서 다루는 이 방법들이 훨씬 .
Git으로 커밋 한 모든 것은 제나 복구할 수 있다. 제한 브랜치에 있었던 것도, --amend 옵션으로 다시 커한 것도
복구할 수 있다(자세한 것은 데이터 복구 에서 다). 하지만 커하지 않고 어버것은 절대로 되돌릴 수 없다.
리모트 저장소
모트 저소를 관리아야 다른 사람과 함일할 수 있다. 모트 저소는 인터이나 크 어가에 있는
소를 한다. 소는 여러 개가 있을 수 있는데 어소는 고 쓰기 모할 수 있고 어소는 기만
할 수 있다. 해서 다른 사람들과 함일한다는 것은 모트 저소를 관리하면서 데이터를 거기에 Push
46
하고 Pull 하는 것이다. 모트 저소를 관리한다는 것은 저소를 추가, 제하는 것뿐만 니라 브랜치를 관리하고
추적할지 지 등을 관리하는 것을 한다. 에는 모트 저소를 관리하는 방법에 대해 명한다.
원격 저장소라 하더라도 로컬 시스템에 위치할 수도 있다.
“remote소라고 이름이 어있어도 이 원소가 사실 은 로시스에 존재할 수도
있다. 여기서 “remote라는 이름은 드시 저소가 크나 인터해 어
있어만 한다는 것을 의하지 않는다. 물론 적인 원가지로 Push, Pull 등의
은 동일하게 사용한다.
리모트 저장소 확인하기
git remote 명령으로 재 프로젝트에 등록된 모트 저소를 인할 수 있다. 이 명령은 모트 저소의 단축
이름을 보여. 소를 Clone 하면 `origin`이라는 모트 저소가 자동으로 등록되기 때문에 `origin`이라는
이름을 볼 수 있다.
$ git clone https://github.com/schacon/ticgit
Cloning into 'ticgit'...
remote: Reusing existing pack: 1857, done.
remote: Total 1857 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done.
Resolving deltas: 100% (772/772), done.
Checking connectivity... done.
$ cd ticgit
$ git remote
origin
-v 옵션을 주어 단축이름과 URL을 함볼 수 있다.
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
모트 저소가 여러 개 있다면 이 명령은 등록된 전부를 보여. 여러 사람과 함하는 모트 저소가
여러개라면 아래와 같과를 을 수도 있다.
47
$ cd grit
$ git remote -v
bakkdoor https://github.com/bakkdoor/grit (fetch)
bakkdoor https://github.com/bakkdoor/grit (push)
cho45 https://github.com/cho45/grit (fetch)
cho45 https://github.com/cho45/grit (push)
defunkt https://github.com/defunkt/grit (fetch)
defunkt https://github.com/defunkt/grit (push)
koke git://github.com/koke/grit.git (fetch)
koke git://github.com/koke/grit.git (push)
origin git@github.com:mojombo/grit.git (fetch)
origin git@github.com:mojombo/grit.git (push)
모트 저소가 여러 개 등록되어 있으면 다른 사람이 기여한 내용(Contributions)을 쉽게 가져올 수 있다.
소에는 Push 한까지 제하기도 하지만 일면에서 Push 한까지는 인할 수 없다.
모트 저데이터를 주고는데 사용하는 다한 프로토콜에 대해서는 서버에 Git 치하기 에서 자세히
살펴보기로 한다.
리모트 저장소 추가하기
이전 절에서도 git clone 명령이 시적으로 origin 모트 저소를 어떻게 추가되는지 명했었지만 수
겉핥으로 살펴을 뿐이었다. 여기에서는 모트 저소를 추가하는 방법을 자세하게 명한다. 기존
렉토리에 새 모트 저소를 쉽게 추가할 수 있는데 git remote add <단축이름> <url> 명령을 사용한다.
$ git remote
origin
$ git remote add pb https://github.com/paulboone/ticgit
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
pb https://github.com/paulboone/ticgit (fetch)
pb https://github.com/paulboone/ticgit (push)
이제 URL 대신에 pb 라는 이름을 사용할 수 있다. 예를 들어 로소에는 없지만 Paul의 저소에 있는 것을
오려면 아래이 실한다.
48
$ git fetch pb
remote: Counting objects: 43, done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 43 (delta 10), reused 31 (delta 5)
Unpacking objects: 100% (43/43), done.
From https://github.com/paulboone/ticgit
Ê* [new branch] master -> pb/master
Ê* [new branch] ticgit -> pb/ticgit
에서 pb/master Paulmaster 브랜치이다. 브랜치를 로컬 브랜치중 하나에 Merge 하거나 Checkout 해서
브랜치 내용을 자세히 인할 수 있다. (브랜치를 어떻게 사용하는지는 Git 브랜 에서 자세히 살펴)
리모트 저장소를 Pull 하거나 Fetch 하기
명했모트 저소에서 데이터를 가오려면 간아래와 같이 실한다.
$ git fetch <remote>
이 명령은 로에는 없지만, 모트 저소에는 있는 데이터를 모온다. 그러면 모트 저소의 모든 브랜치를
에서 접할 수 있어서 제든지 Merge를 하거나 내용을 살펴볼 수 있다.
소를 Clone 하면 명령은 자동으로 모트 저소를 “origin” 이라는 이름으로 추가한다. 서 나중에 git fetch
origin 명령을 실하면 Clone 한 이후에(은 마지으로 가온 이후에) 수정된 것을 모온다. git fetch
명령은 모트 저소의 데이터를 모로 가오지만, 자동으로 Merge 하지 않는다. 서 당신이 로에서 하던
을 정하고 나서 수동으로 Merge 한다.
쉽게 git pull 명령으로 모트 저브랜치에서 데이터를 가져올 뿐만 니라 자동으로 로컬 브랜Merge
수 있다(다음 섹션Git 브랜 에서 좀더 자세히 살펴). git clone 명령은 자동으로 로master
브랜치가 모트 저소의 master 브랜치를 추적하도록 한다(물론 리모트 저소에 master 브랜치가 있다는 가정에서).
git pull 명령은 Clone 한 서버에서 데이터를 가오고 그 데이터를 자동으로 재 작하는 코드Merge
.
리모트 저장소에 Push 하기
프로젝트를 유하고 을 때 Upstream 소에 Push 할 수 있다. 이 명령은 git push <모트 이름>
<브랜 이름>`으로 순하다. master 브랜치를 `origin 서버에 Push 하려면(다시 하지만 Clone 하면 보
자동으로 origin 이름이 생성된다) 아래와 같이 서버에 Push 한다.
$ git push origin master
이 명령은 Clone 모트 저소에 쓰기 한이 있고, Clone 하고 난 이후 무도 Upstream 소에 Push 하지
않았을 때만 사용할 수 있다. 다시 해서 Clone 한 사람이 여러 명 있을 때, 다른 사람이 Push 한 후에 Push 하려고 하면
Push 할 수 없다. 저 다른 사람이 작한 것을 가져와Merge 한 후에 Push 할 수 있다. Git 브랜 에서 서버에 Push
하는 방법에 대해 자세히 명할 것이다.
49
리모트 저장소 살펴보기
git remote show <모트 이름> 명령으로 모트 저소의 구체적인 정보를 인할 수 있다. origin
단축이름으로 이 명령을 실하면 아래와 같은 정보를 볼 수 있다.
$ git remote show origin
* remote origin
Ê Fetch URL: https://github.com/schacon/ticgit
Ê Push URL: https://github.com/schacon/ticgit
Ê HEAD branch: master
Ê Remote branches:
Ê master tracked
Ê dev-branch tracked
Ê Local branch configured for 'git pull':
Ê master merges with remote master
Ê Local ref configured for 'git push':
Ê master pushes to master (up to date)
모트 저소의 URL과 추적하는 브랜치를 출력한다. 이 명령은 git pull 명령을 실할 때 master 브랜Merge
브랜치가 무엇인지 보여 . git pull 명령은 모트 저브랜치의 데이터를 모오고 나서 자동으로
Merge 할 것이다. 고 가온 모든 모트 저소 정보도 출력한다.
좀 더 Git을 열심히 사용하다 보면 git remote show 명령으로 더 많은 정보를 보는 이 온다. 여러분도 가는
아래와 같시지(- 다수의 브랜치를 사용하는 시지)를 볼 것이다.
50
$ git remote show origin
* remote origin
Ê URL: https://github.com/my-org/complex-project
Ê Fetch URL: https://github.com/my-org/complex-project
Ê Push URL: https://github.com/my-org/complex-project
Ê HEAD branch: master
Ê Remote branches:
Ê master tracked
Ê dev-branch tracked
Ê markdown-strip tracked
Ê issue-43 new (next fetch will store in
remotes/origin)
Ê issue-45 new (next fetch will store in
remotes/origin)
Ê refs/remotes/origin/issue-11 stale (use 'git remote prune' to
remove)
Ê Local branches configured for 'git pull':
Ê dev-branch merges with remote dev-branch
Ê master merges with remote master
Ê Local refs configured for 'git push':
Ê dev-branch pushes to dev-branch
(up to date)
Ê markdown-strip pushes to markdown-strip
(up to date)
Ê master pushes to master
(up to date)
브랜치명을 생하고 git push 명령을 실할 때 어떤 브랜치가 어떤 브랜치로 Push 되는지 보여. 아직
오지 않은 모트 저소의 브랜치는 어것들이 있는지, 서버에서는 제됐지만 아직 가지고 있는 브랜치는 어
것인지, git pull 명령을 실했을 때 자동으로 Merge 브랜치는 어것이 있는지 보여.
리모트 저장소 이름을 바꾸거나 리모트 저장소를 삭제하기
git remote rename 명령으로 모트 저소의 이름을 경할 수 있다. 예를 들어 pb paul 경하려면 git
remote rename 명령을 사용한다.
$ git remote rename pb paul
$ git remote
origin
paul
에서 관리하던 모트 저소의 브랜치 이름도 바뀐다는 을 생각해. 까지 pb/master 모트 저
브랜치를 사용했으면 이제는 paul/master 라고 사용해한다.
모트 저소를 제해한다면 git remote remove git remote rm 명령을 사용한다. 서버 정보가
었을 때, 더는 도의 러가 요하지 않을 때, 더는 기여자가 활동하지 않을 때 요하다.
51
$ git remote remove paul
$ git remote
origin
와 같방법으로 모트 저소를 제하면 해당 모트 저소에 관련된 추적 브랜치 정보나 모든 정 내용도 함
제된다.
태그
다른 VCS처럼 Git그를 지원한다. 사람들은 보통 릴리즈할 때 사용한다(v1.0, 등등). 에는 그를 회하고
생성하는 그의 명한다.
태그 조회하기
git tag 명령으로 (-l, `--list`옵션) 만들어진 태그가 있는지 인할 수 있다.
$ git tag
v0.1
v1.3
이 명령은 알순서로 그를 보여. 사실 순서는 로 중요한 게 니다.
색 패을 사용하여 그를 할 수 있다. Git 소스 저소는 500여 개의 그가 있다. 1.8.5 버전의 그들만
하고 으면 아래와 같이 실한다.
$ git tag -l "v1.8.5*"
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5-rc2
v1.8.5-rc3
v1.8.5.1
v1.8.5.2
v1.8.5.3
v1.8.5.4
v1.8.5.5
52
와일드카드를 사용하여 Tag 리스트를 확인하려면 -l, --list 옵션을 지정
순히 모든 Tag 목록을 인하기 위해 git tag 명령을 실했을 때 -l 또는 --list 옵션
적용된 것과 동일한 과가 출력된다.
하지만 일드드를 사용하여 그 목록을 하는 경우에는 드시 -l 또는 --list 옵션
원하는 과를 을 수 있다.
태그 붙이기
Git그는 Lightweight Annotated 그로 가 있다.
Lightweight 그는 브랜한데 브랜치처럼 가키는 지신 커으로 이동시키지 않는다. 순히 특정
에 대한 포인터일 뿐이다.
한편 Annotated 그는 Git 데이터이스에 그를 만든 사람의 이름, 일과 그를 만든 , 시지도
한다. GPG(GNU Privacy Guard)로 서명할 수도 있다. 적으로 Annotated 그를 만들어 이 모든 정보를 사용할
수 있도록 하는 것이 좋다. 하지만 시로 생성하는 그거나 이러한 정보를 유지할 요가 없는 경우에는 Lightweight
그를 사용할 수도 있다.
Annotated 태그
Annotated 그를 만드는 방법은 간하다. tag 명령을 실할 때 -a 옵션을 추가한다.
$ git tag -a v1.4 -m "my version 1.4"
$ git tag
v0.1
v1.3
v1.4
-m 옵션으로 그를 저할 때 시지를 함할 수 있다. 명령을 실할 때 시지를 입력하지 않으면 Git은 편기를
.
git show 명령으로 그 정보정보를 모두 확인할 수 있다.
53
$ git show v1.4
tag v1.4
Tagger: Ben Straub <ben@straub.cc>
Date: Sat May 3 20:19:12 2014 -0700
my version 1.4
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
Ê changed the version number
정보를 보여주기 전에 그를 만든 사람이 누구인지, 그를 만들었는지, 시지가 무엇인지
보여.
Lightweight 태그
Lightweight 그는 기적으로 일에 커밋 체을 저하는 것뿐이다. 다른 정보는 저하지 않는다. Lightweight
그를 만들 때는 -a, -s, -m 옵션을 사용하지 않는다. 이름만 달아줄 뿐이다.
$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5
그에 git show 를 실하면 도의 그 정보를 인할 수 없다. 이 명령은 순히 커정보만을 보여.
$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
Ê changed the version number
나중에 태그하기
예전 커에 대해서도 그할 수 있다. 히스토리아래와 같다고 가정한다.
54
$ git log --pretty=oneline
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'
a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support
0d52aaab4479697da7686c15f77a3d64d9165190 one more thing
6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function
4682c3261057305bdd616e23b64b0857d832627b added a todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a started write support
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
“updated rakefilev1.2그하지 못했다고 해도 나중에 그를 일 수 있다. 특정 커그하기 위해서
명령의 에 커밋 체을 명시한다(긴 체을 전부 사용할 요는 없다).
$ git tag -a v1.2 9fceb02
이제 아래와 같이 만든 그를 인한다.
$ git tag
v0.1
v1.2
v1.3
v1.4
v1.4-lw
v1.5
$ git show v1.2
tag v1.2
Tagger: Scott Chacon <schacon@gee-mail.com>
Date: Mon Feb 9 15:32:16 2009 -0800
version 1.2
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: Magnus Chacon <mchacon@gee-mail.com>
Date: Sun Apr 27 20:43:35 2008 -0700
Ê updated rakefile
...
태그 공유하기
git push 명령은 자동으로 모트 서버에 그를 전송하지 않는다. 그를 만들었으면 서버에 도로 Push 한다.
브랜치를 유하는 것과 방법으로 할 수 있다. `git push origin <그 이름>`을 실한다.
55
$ git push origin v1.5
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done.
Total 14 (delta 3), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
Ê* [new tag] v1.5 -> v1.5
그를 여러 개 Push 하고 으면 --tags 옵션을 추가하여 git push 명령을 실한다. 이 명령으로
모트 서버에 없는 그를 모전송할 수 있다.
$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
Ê* [new tag] v1.4 -> v1.4
Ê* [new tag] v1.4-lw -> v1.4-lw
이제 가 저소에서 Clone 하거나 Pull을 하면 모든 그 정보도 함전송된다.
태그를 Checkout 하기
예를 들어 그가 특정 버전을 가키고 있고, 특정 버전의 일을 아웃 해서 인하고 다면 다음과 이 실한다.
단 태그를 아웃하면(브랜치를 아웃 하는 것이 니라면) “detached HEAD”(나온 HEAD) 가 되며
일부 Git 관련 브랜치에서 작하는 것과 다게 동작할 수 있다.
56
$ git checkout 2.0.0
Note: checking out '2.0.0'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
Ê git checkout -b <new-branch>
HEAD is now at 99ada87... Merge pull request #89 from schacon/appendix-
final
$ git checkout 2.0-beta-0.1
Previous HEAD position was 99ada87... Merge pull request #89 from
schacon/appendix-final
HEAD is now at df3f601... add atlas.json and cover image
“detached HEAD”(나온 HEAD) 에서는 작을 하고 커을 만들면, 그는 그대로 있으나 새로운 커
하나 인 상가 되고 새 커에 도달할 수 있는 방법이 따로 없게 된다. 물론 의 해시 을 정히 기하고 있으면
하다. 특정 그의 상에서 새로 작성한 커이 버그 와 같이 의있도록 하려면 드시 브랜치를 만들어서
하는 것이 좋다.
$ git checkout -b version2 v2.0.0
Switched to a new branch 'version2'
물론 브랜치를 만든 후에 version2 브랜치에 커하면 브랜치는 데이트된다. 하지만, v2.0.0 그는
키는 커하지 않았으내용이 가키는 커이 다다는 것을 알 수 있다.
Git Alias
Git의 기를 마치기 전에 Git을 좀 더 쉽고 편하게 쓸 수 있게 만들어 Alias 라는 알려주려 한다. 는 이 책에서
을 다시 거하지 않고 이런 을 알고 있다고 가정한다. 서 알고 있는 것이 좋다.
명령을 완벽하게 입력하지 않으면 Git은 알지 못한다. Git의 명령을 전부 입력하는 것이 다면 git config
사용하여 각 명령의 Alias을 쉽게 만들 수 있다. 아래Alias을 만드는 예이다.
57
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
이제 git commit 대신 git ci 만으로도 커할 수 있다. Git을 계속 사용한다면 다른 명령어도 자주 사용하게 될
것이다. 주저고 자주 사용하는 명령은 Alias을 만들어 편하게 사용하시.
있는 명령을 편하고 새로운 명령으로 만들어 사용할 수 있다. 예를 들어 일을 Unstaged 경하는 명령을
만들어서 편함을 수 있다. 아래와 같unstage 라는 Alias을 만든다.
$ git config --global alias.unstage 'reset HEAD --'
아래 두 명령은 동일한 명령이다.
$ git unstage fileA
$ git reset HEAD -- fileA
. 추가로 last 명령을 만들어 보자:
$ git config --global alias.last 'log -1 HEAD'
이제 최근 을 좀 더 쉽게 인할 수 있다.
$ git last
commit 66938dae3329c7aebe598c2246a8e6af90d04646
Author: Josh Goebel <dreamer3@example.com>
Date: Tue Aug 26 19:48:51 2008 +0800
Ê test for current head
Ê Signed-off-by: Scott Chacon <schacon@example.com>
이것으로 쉽게 새로운 명령을 만들 수 있다. Git의 명령어뿐만 니라 외부 명령어도 실할 수 있다. ! 를 제일
추가하면 외부 명령을 실한다. 커스스크트를 만들어서 사용할 때 우 유용하다. 아래 명령은 git visual
이라고 입력하면 gitk 가 실된다.
$ git config --global alias.visual '!gitk'
58
요약
이제 우는 로에서 사용할 수 있는 Git 명령에 대한 기추었다. 소를 만들고 Clone 하는 방법, 수정하고
나서 Stage 하고 커하는 방법, 소의 히스토리회하는 방법 등을 살펴보았다. 이어지는 에서는 Git의 가
력한 기브랜치 모을 살펴볼 것이다.
59
Git 브랜치
모든 버전 관리 시스브랜치를 지원한다. 개발을 하다 보면 코드를 여러 개로 사해하는 일이 자주 생. 코드를
통째사하고 나서 원코드는 상없이 독립적으로 개발을 진행할 수 있는데, 독립적으로 개발하는 것이
브랜치다.
사람들은 브랜치 모Git고의 장점이라고, Git이 다른 것들과 분되는 특이라고 한다. 떤 점이 그
한 것일까. Git브랜치는 우 가. 간에 브랜치를 새로 만들고 브랜치 사이를 이동할 수 있다. 다른 버전
관리 시스과는 달Git브랜치를 만들어 작하고 나중에 Merge 하는 방법한다. 심지어 하루에 수
번씩해도 괜찮. Git 브랜치에 능숙해지면 개발 방식전히 바고 다른 도를 사용할 수 없게 된다.
브랜치란 무엇인가
Git브랜치를 다루는 과정을 이해하려면 우Git이 데이터를 어떻게 저하는지 알아야 한다.
Git은 데이터를 Change Set이나 경사(Diff)으로 기록하지 않고 일의 스냅샷으로 기록한다는 것을 시작하기 에서
보여.
하면 GitStaging Area에 있는 데이터의 스냅샷에 대한 포인터, 저자나 커밋 메시지 타데이터, 이전
에 대한 포인터 등을 포함하는 커(Object)를 저한다. 이전 커포인터가 있어서 재 커이 무엇을
으로 바었는지를 알 수 있다. 을 제외한 나지 커은 이전 커포인터가 적어도 하나있고 브랜치를
Merge 밋 같은 경우에는 이전 커포인터가 여러 개 있다.
일이 3개 있는 디렉토리가 하나 있고 이 일을 Staging Area에 저하고 커하는 예제를 살펴 보자. 일을 Stage
하면 Git 소에 일을 저하고(Git은 이것을 Blob이라고 부른다) Staging Area에 해당 일의 을 저한다
(시작하기 에서 살펴SHA-1을 사용한다).
$ git add README test.rb LICENSE
$ git commit -m 'The initial commit of my project'
git commit 으로 커하면 저 루트 디렉토리와 각 하위 디렉토리의 트과 함소에 저한다.
그다음에 커를 만들고 타데이터루트 디렉토리 를 가키는 포인터 정보를 커
한다. 요하면 제든지 스냅샷을 다시 만들 수 있다.
이 작을 마치고 나면 Git 소에는 다개의 데이터 개가 생. 일에 대한 Blob 세 개, 일과 디렉토리
구조가 들어 있는 트하나, 타데이터루트 트를 가키는 포인터가 담긴 하나이다.
60
그림 9. 커밋과 트리 데이터
다시 일을 수정하고 커하면 이전 커이 무엇인지도 저한다.
그림 10. 커밋과 이전 커밋
Git브랜치는 커사이를 가게 이동할 수 있는 어포인터 은 것이다. 적으로 Gitmaster 브랜치를 만든다.
처음 커하면 이 master 브랜치가 생성된 커을 가. 이후 커을 만들면 master 브랜치는 자동으로 가
마지을 가.
Git 버전 관리 시스에서 “master” 브랜치는 특하지 않다. 다른 브랜다른 것이 없다. 다만
모든 저소에서 “master” 브랜치가 존재하는 이유는 git init 명령으로 할 때 자동으로
만들어브랜치를 써 다른 이름으로 경하지 않기 때문이다.
61
그림 11. 브랜치와 커밋 히스토리
새 브랜치 생성하기
브랜치를 하나 새로 만들면 어. 브랜치를 하나 만들어서 . 아래와 같git branch 명령으로 testing
브랜치를 만든다.
$ git branch testing
새로 만든 브랜치도 지금 작하고 있던 마지을 가.
62
그림 12. 한 커밋 히스토리를 가리키는 두 브랜치
지금 작중인 브랜치가 무엇인지 Git은 어떻게 할까. 다른 버전 관리 시스과는 달Git'HEAD’라는 특수한
포인터가 있다. 이 포인터는 지금 작하는 로컬 브랜치를 가. 브랜치를 새로 만들었지만, Git아직 master
브랜치를 가키고 있다. git branch 명령은 브랜치를 만들기만 하고 브랜치를 기지 않는다.
그림 13. 현재 작업 중인 브랜치를 가리키는 HEAD
git log 명령에 --decorate 옵션을 사용하면 쉽게 브랜치가 어을 가키는지도 인할 수 있다.
63
$ git log --oneline --decorate
f30ab (HEAD -> master, testing) add feature #32 - ability to add new
formats to the central interface
34ac2 Fixed bug #1328 - stack overflow under certain conditions
98ca9 The initial commit of my project
“master” “testing” 이라는 브랜치가 f30ab 에 위치하여 이런으로 브랜치가 가키는 커인할 수
있다.
브랜치 이동하기
git checkout 명령으로 다른 브랜치로 이동할 수 있다. testing 브랜치로 바보자.
$ git checkout testing
게 하면 HEADtesting 브랜치를 가.
그림 14. HEADtesting 브랜치를 가리킴
, 이제 핵심이 보일 거다! 을 새로 한 해보자.
64
$ vim test.rb
$ git commit -a -m 'made a change'
그림 15. HEAD가 가리키는 testing 브랜치가 새 커밋을 가리킴
이 부분이 . 새로 커해서 testing 브랜치는 으로 이동했다. 하지만, master 브랜치는 여전히 이전 커
. master 브랜치로 되돌아가보자.
$ git checkout master
그림 16. HEADCheckout 한 브랜치로 이동함
금 실한 명령이 한 일은 가지다. master 브랜치가 가키는 커HEAD가 가키게 하고 렉토리
일도 그 시으로 되려 놓았다. 으로 커을 하면 다른 브랜치의 작들과 개로 진행되기 때문에 testing
브랜치에서 시로 작하고 원master 브랜치로 돌아와서 하던 일을 계속할 수 있다.
65
브랜치를 이동하면 워킹 디렉토리의 파일이 변경된다
브랜치를 이동하면 렉토리일이 경된다는 을 기한다. 이전에 작했던
브랜치로 이동하면 렉토리일은 그 브랜치에서 가마지으로 했던 작내용으로
경된다. 경시 문제가 있어 브랜치를 이동시키는게 한 경우 Git브랜치 이동 명령을
하지 않는다.
일을 수정하고 다시 커을 해보자.
$ vim test.rb
$ git commit -a -m 'made other changes'
프로젝트 히스토리는 분리돼 진행한다(라지는 브랜). 브랜치를 하나 만들어 그 브랜치에서 일을 좀 하고, 다시
래 브랜치로 되돌아와서 다른 일을 했다. 내용은 서로 독립적으로 각 브랜치에 존재한다. 사이를 자유
이동하다가 때가 되면 두 브랜치를 Merge 한다. branch, checkout, commit 명령을 써서 이다.
그림 17. 갈라지는 브랜치
git log 명령으로 쉽게 인할 수 있다. 브랜치가 가키고 있는 히스토리가 무엇이고 어떻게 나왔는지
보여. git log --oneline --decorate --graph --all 이라고 실하면 히스토리를 출력한다.
66
$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) made other changes
| * 87ab2 (testing) made a change
|/
* f30ab add feature #32 - ability to add new formats to the
* 34ac2 fixed bug #1328 - stack overflow under certain conditions
* 98ca9 initial commit of my project
실제로 Git브랜치는 어한 커을 가키는 40자의 SHA-1 일에 과하기 때문에 만들기도 쉽고
지우기도 쉽다. 새로 브랜치를 하나 만드는 것은 41바이트 크기의 일을(40와 줄 문자) 하나 만드는 것에
과하다.
브랜치가 요할 때 프로젝트를 통째사해하는 다른 버전 관리 구와 Git이는 명하다. 통째사하는
은 프로젝트 크기에 따라 다르겠지만 수십 초에서 수분까지 걸. 그에 비해 Git은 순간이다. 게다가 커을 할
때마다 이전 커의 정보를 저하기 때문에 Merge 할 때 어디서부터(Merge Base) 하는지 . 이런 특
개발자들이 수시로 브랜치를 만들어 사용하게 한다.
이제 브랜치를 수시로 만들고 사용해하는지 알보자.
브랜치와 Merge 의 기초
실제 개발과정에서 을 만한 예제를 하나 살펴보자. 브랜Merge는 보이런 으로 진행한다.
1. 웹사이트가 있고 가 작진행하고 있다.
2. 새로운 이를 처할 새 Branch를 하나 생성한다.
3. 새로 만든 Branch에서 작진행한다.
이때 중요한 문제가 생서 그것을 해하는 Hotfix저 만들어한다. 그러면 아래와 같이 할 수 있다.
1. 새로운 이를 처하기 이전의 운영(Production) 브랜치로 이동한다.
2. Hotfix 브랜치를 새로 하나 생성한다.
3. 수정한 Hotfix 스트를 마치고 운영 브랜치로 Merge 한다.
4. 다시 작하던 브랜치로 옮겨가서 하던 일 진행한다.
브랜치의 기초
저 지금 작하는 프로젝트에서 이전에 master 브랜치에 커몇 번 했다고 가정한다.
67
그림 18. 현재 커밋 히스토리
슈 관리 시스에 등록된 53를 처한다고 하면 이 이중할 수 있는 브랜치를 새로 하나 만든다. 브랜치를
만들면서 Checkout까지 한 에 하려면 git checkout 명령에 -b 라는 옵션을 추가한다.
$ git checkout -b iss53
Switched to a new branch "iss53"
위 명령은 아래 명령을 여놓은 것이다.
$ git branch iss53
$ git checkout iss53
그림 19. 브랜치 포인터를 새로 만듦
iss53 브랜치를 Checkout 했기 때문에(, HEAD iss53 브랜치를 가) 가 일을 하고 커하면 iss53
브랜치가 으로 나간다.
68
$ vim index.html
$ git commit -a -m 'added a new footer [issue 53]'
그림 20. 진행 중인 iss53 브랜치
다른 상을 가정해보자. 만드는 사이트에 문제가 생시 고한다. 버그를 해Hotfixiss53 이는
것을 지하기 위해 iss53 관련된 코드를 어가에 저고 원운영 환경의 소스로 복구한다. Git
사용하면 이런 노력을 들일 요 없이 그master 브랜치로 돌아가면 된다.
지만, 브랜치를 이동하려면 해할 일이 있다. 아직 하지 않은 일이 Checkout 브랜나면 브랜치를
경할 수 없다. 브랜치를 경할 때는 렉토리를 정하는 것이 좋다. 이런 문제를 다루는 방법(주로, Stash이나
Amend에 대해) 나중에 StashingCleaning 에서 다것이다. 지금은 작하던 것을 모하고 master
브랜치로 :
$ git checkout master
Switched to branch 'master'
이때 렉토리53를 시작하기 이전 모습으로 되려지기 때문에 새로운 문제에 중할 수 있는 환경이
만들어. Git은 자동으로 렉토리일들을 추가하고, 지우고, 수정해서 Checkout 브랜치의 마지
냅샷으로 되려 놓는다는 것을 기한다.
스가 생을 때를 살펴보자. `hotfix`라는 브랜치를 만들고 새로운 이를 해할 때까지 사용한다.
$ git checkout -b hotfix
Switched to a new branch 'hotfix'
$ vim index.html
$ git commit -a -m 'fixed the broken email address'
[hotfix 1fb7853] fixed the broken email address
Ê1 file changed, 2 insertions(+)
69
그림 21. master 브랜치에서 갈라져 나온 hotfix 브랜치
운영 환경에 적용하려면 문제를 제대로 고는지 스트하고 적으로 운영환경에 배포하기 위해 hotfix 브랜치를
master 브랜치에 합한다. git merge 명령으로 아래와 같이 한다.
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
Êindex.html | 2 ++
Ê1 file changed, 2 insertions(+)
Merge 시지에서 “fast-forward” 가 보이는가. hotfix 브랜치가 가키는 C4 C2 에 기브랜치이기
때문에 브랜치 포인터는 Merge 과정 없이 그저 신 커으로 이동한다. 이런 Merge 방식“Fast forward” 라고
부른다. 다시 A 브랜치에서 다른 B 브랜치를 Merge 할 때 B 브랜치가 A 브랜치 이후의 커을 가키고 있으면 그저
A 브랜치가 B 브랜동일한 커을 가키도록 이동시뿐이다.
이제 hotfix` `master 브랜치에 포함됐고 운영환경에 적용할 수 있는 상가 되었다고 가정해보자.
70
그림 22. Merge hotfix 같은 것을 가리키는 master 브랜치
한 문제를 해하고 master 브랜치에 적용하고 나면 다시 일하던 브랜치로 돌아한다. 이제 더 이상 요없는
hotfix 브랜치는 제한다. git branch 명령에 -d 옵션을 주고 브랜치를 제한다.
$ git branch -d hotfix
Deleted branch hotfix (3a0874c).
자 이제 이53을 처하던 환경으로 되돌아가서 하던 일을 계속 하자.
$ git checkout iss53
Switched to branch "iss53"
$ vim index.html
$ git commit -a -m 'finished the new footer [issue 53]'
[iss53 ad82d7a] finished the new footer [issue 53]
1 file changed, 1 insertion(+)
71
그림 23. master와 별개로 진행하는 iss53 브랜치
위에서 작hotfix iss53 브랜치에 영치지 않는다는 을 이해하는 것이 중요하다. git merge
master 명령으로 master 브랜치를 iss53 브랜치에 Merge 하면 iss53 브랜치에 hotfix 가 적용된다. 니면
iss53 브랜치가 master Merge 할 수 있는 수이 될 때까지 기다렸다가 Merge 하면 hotfix iss53 브랜치가
.
Merge 의 기초
53를 다 구현하고 master 브랜치에 Merge 하는 과정을 살펴보자. iss53 브랜치를 master 브랜치에 Merge
하는 것은 서 살펴hotfix 브랜치를 Merge 하는 것과 비하다. git merge 명령으로 합칠 브랜치에서 합
브랜치를 Merge 하면 된다.
$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html | 1 +
1 file changed, 1 insertion(+)
hotfix Merge 했을 때와 메시지가 다. 브랜치가 가키는 커Merge 브랜치의 상이
Git'Fast-forward’Merge 하지 않는다. 이 경우에는 Git은 각 브랜치가 가키는 커밋 두 와 공통 조상 하나를
사용하여 3-way Merge를 한다.
72
그림 24. 커밋 3개를 Merge
순히 브랜치 포인터를 신 커으로 기는 게 니라 3-way Merge 과를 도의 커으로 만들고 나서 해당
브랜치가 그 커을 가키도록 이동시. 서 이런 커은 부모가 여러 개고 Merge 이라고 부른다.
그림 25. Merge 커밋
iss53 브랜치를 masterMerge 하고 나면 더는 iss53 브랜치가 요 없다. 다음 명령으로 브랜치를 제하고 이
를 처시한다.
$ git branch -d iss53
충돌의 기초
73
3-way Merge가 실할 때도 있다. Merge 하는 두 브랜치에서 일의 한 부분을 동시에 수정하고 Merge
하면 Git은 해당 부분을 Merge 하지 못한다. 예를 들어, 53슈와 hotfix 은 부분을 수정했다면 GitMerge
하지 못하고 아래와 같(Conflict) 시지를 출력한다.
$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
Git은 자동으로 Merge 하지 못해서 새 커이 생기지 않는다. 경사을 개발자가 해하지 않는 한 Merge
과정을 진행할 수 없다. Merge 이 일어을 때 Git이 어떤 파일을 Merge 할 수 없었는지 살펴보려면 git status
명령을 이용한다.
$ git status
On branch master
You have unmerged paths.
Ê (fix conflicts and run "git commit")
Unmerged paths:
Ê (use "git add <file>..." to mark resolution)
Ê both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")
이 일어난 일은 unmerged 시된다. Git이 난 부분을 표준 형식에 따라 시해. 그러면
개발자는 해당 부분을 수동으로 해한다. 난 부분은 아래와 같시된다.
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
Êplease contact us at support@github.com
</div>
>>>>>>> iss53:index.html
======= 의 내용은 HEAD 버전(merge 명령을 실할 때 작하던 master 브랜)의 내용이고 아래iss53
브랜치의 내용이다. 을 해하려면 위이나 아래내용 중에서 고거나 새로 작성하여 Merge 한다. 아래
새로 작성하여 을 해하는 예제다.
<div id="footer">
please contact us at email.support@github.com
</div>
74
에서 져와서 새로 수정했다. <<<<<<<, =======, >>>>>>>` 포함된 제했다.
부분을 하고 `git add 명령으로 다시 Git에 저한다.
다른 Merge 을 해할 수 있다. git mergetool 명령으로 실한다.
$ git mergetool
This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse
diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge
Merging:
index.html
Normal merge conflict for 'index.html':
Ê {local}: modified file
Ê {remote}: modified file
Hit return to start merge resolution tool (opendiff):
구 말고 사용할 수 있는 다른 Merge 도 있는데(Mac에서는 opendiff 가 실된다), “one of the following
tools.부분에 보여. 여기에 시된 도중 하나를 고를 수 있다.
Merge 시에 발생한 을 다루는 더 어렵고 요상한 내용은 Merge 에서 다루기로 한다.
Merge 하면 GitMerge 했는지 . 다고 입력하면 자동으로 git add 가 수되고 해당
일이 Staging Area에 저된다. git status 명령으로 이 해된 상인지 다시 한번 확인해볼 수 있다.
$ git status
On branch master
All conflicts fixed but you are still merging.
Ê (use "git commit" to conclude merge)
Changes to be committed:
Ê modified: index.html
을 해하고 나서 해당 일이 Staging Area에 저됐는지 인했으면 git commit 명령으로 Merge 한 것을
한다. 을 해하고 Merge 할 때는 커밋 메시지가 아래와 같.
75
Merge branch 'iss53'
Conflicts:
Ê index.html
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
# .git/MERGE_HEAD
# and try again.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
# modified: index.html
#
어떻게 을 해했고 좀 더 인해하는 부분은 무엇이고 게 해했는지에 대해서 자세하게 기록한다. 자세한
기록은 나중에 이 Merge 을 이해하는데 도움을 .
브랜치 관리
지금까지 브랜치를 만들고, Merge 하고, 제하는 방법에 대해서 살펴. 브랜치를 관리하는 데 요한 다른 명령도
살펴보자.
git branch 명령은 순히 브랜치를 만들고 제하는 것이 니다. 무런 옵션 없이 실하면 브랜치의 목록을
보여.
$ git branch
Ê iss53
* master
Ê testing
* 기호가 어 있는 master 브랜치는 Checkout 해서 작하는 브랜치를 나타. , 지금 수정한 내용을
하면 master 브랜치에 커되고 포인터가 으로 한 계 나간다. git branch -v 명령을 실하면
브랜치마다 마지밋 메시지도 함보여.
76
$ git branch -v
Ê iss53 93b412c fix javascript issue
* master 7a98805 Merge branch 'iss53'
Ê testing 782fd34 add scott to the author list in the readmes
브랜치가 지금 어인지 인하기에 좋은 옵션도 있다. Checkout 브랜치를 기으로 --merged
--no-merged 옵션을 사용하여 Merge 브랜치인지 그지 않은지 해 볼 수 있다. git branch --merged
명령으로 이Merge 브랜치 목록을 인한다.
$ git branch --merged
Ê iss53
* master
iss53 브랜치는 에서 이Merge 했기 때문에 목록에 나타난다. * 기호가 어 있지 않은 브랜치는 git branch
-d 명령으로 제해도 되는 브랜치다. 다른 브랜Merge 했기 때문에 제해도 정보를 지 않는다.
대로 Checkout 브랜치에 Merge 하지 않은 브랜치를 살펴보려면 git branch --no-merged 명령을
사용한다.
$ git branch --no-merged
Ê testing
위에는 없었던 다른 브랜치가 보인다. 아직 Merge 하지 않은 커고 있기 때문에 git branch -d 명령으로
제되지 않는다.
$ git branch -d testing
error: The branch 'testing' is not fully merged.
If you are sure you want to delete it, run 'git branch -D testing'.
Merge 하지 않은 브랜치를 제로 제하려면 -D 옵션으로 제한다.
77
위에서 명한 --merged, --no-merged 옵션을 사용할 때 커이나 브랜치 이름을 지정해주지
않으면 현재 브랜치를 기으로 Merge 되거나 Merge 되지 않은 내용을 출력한다.
위 명령을 사용할 때 특정 브랜치를 기으로 Merge 되거나 Merge 되지 않은 브랜치 정보를
살펴보려면 명령에 브랜치 이름을 지정해주면 된다. 예를 들어 master 브랜치에 아직 Merge되지
않은 브랜치를 살펴보려면 다음과 은 명령을 실한다.
$ git checkout testing
$ git branch --no-merged master
Ê topicA
Ê featureB
브랜치 워크플로
브랜치를 만들고 Merge 하는 것을 어디에 써할까. 이 절에서는 Git 브랜치가 유용한 가지 크플로를 살펴.
여기서 명하는 크플로를 개발에 적용하면 도움이 될 것이다.
Long-Running 브랜치
Git꼼꼼하게 3-way Merge를 사용하기 때문에 기간에 걸서 한 브랜치를 다른 브랜여러 Merge 하는 것이
운 편이다. 서 개발 과정에서 요한 용도에 따라 브랜치를 만들어 고 계속 사용할 수 있다. 고 정기적으로
브랜치를 다른 브랜치로 Merge 한다.
이런 접근법에 따라서 Git 개발자가 많이 호하는 크플로가 하나 있다. 배포했거나 배포할 코드만 master 브랜치에
Merge 해서 정 버전의 코드만 master 브랜치에 . 개발을 진행하고 하는 브랜치는 develop 이나 next
라는 이름으로 추가로 만들어 사용한다. 브랜치는 정 상가 되지만, 정 상를 유지해하는 것이
니다. 스트를 거정적이라고 판되면 master 브랜치에 Merge 한다. 토픽 브랜(서 살펴iss53
브랜은 호브랜)에도 적용할 수 있는데, 해당 토픽을 처하고 스트해서 버그도 없고 정적이면 그때
Merge 한다.
사실 우기하는 것은 커을 가키는 포인터에 대한 기다. 포인터를 만들고 수정하고 분하고 합치는지에
대한 것이다. 개발 브랜치는 적으로 히스토리를 만들어 나가고 브랜치는 이만든 히스토리
간다.
그림 26. 안정적인 브랜치일수록 커밋 히스토리가 뒤쳐짐
실에서 분히 스트하고 실전에 배치하는 과정으로 보면 이해하기 쉽다
78
그림 27. 각 브랜치를 하나의 실험실로 생각
코드를 여러 계로 나정성을 여가며 운영할 수 있다. 프로젝트 모가 크면 proposed pu (proposed
updates)라는 이름의 브랜치를 만들고 next master 브랜치에 아직 Merge 비가 되지 않은 것을 일Merge
. 중요한 개념은 브랜치를 이용해 여러 계에 걸해 나가면서 분히 가 됐을 때 브랜치로
Merge 한다는 이다. 다시 해서 Long-Running브랜치가 여러 개일 요는 없지만 정유용하다는 이다. 특히
모가 크고 복잡한 프로젝트일수록 그 유용성이 짝 빛난다.
토픽 브랜치
토픽 브랜치는 프로젝트 크기에 상없이 유용하다. 토픽 브랜치는 어한 가지 주제나 작을 위해 만든 은 호
브랜치다. 다른 버전 관리 시스에서는 이런 브랜치를 적이 없을 것이다. Git다른 버전 관리 에서는
브랜치를 하나 만드는 데 비용이 든다. Git에서는 우 일상적으로 브랜치를 만들고 Merge 하고 제한다.
서 사용한 iss53 이나 hotfix 브랜치가 토픽 브랜치다. 브랜치를 새로 만들고 어느 정도 커하고 나서 다시
master 브랜치에 Merge 하고 브랜제도 해 보았다. 주제브랜치를 만들고 각각은 독립돼 있기 때문에
쉽게 컨텍스트 사이를 옮겨 수 있다. 로 나서 일하면 내용하기에도, 스트하기에도 더 편하다.
을 하루든 한 달이든 유지하다가 master 브랜치에 Merge 할 시이 되면 순서에 계없이 그때 Merge 하면 된다.
master 브랜치를 checkout 한 상에서 어을 한다고 해보자. 한 이를 처하기 위해서 iss91 브랜치를
만들고 해당 작을 한다. 은 이를 다른 방법으로 해해보고 을 때도 있다. iss91v2 브랜치를 만들고 다른 방법
시도해 . 신할 수 없는 이디어를 적용해보기 위해 다시 master 브랜치로 되돌아가서 dumbidea 브랜치를 하나
더 만든다. 지금까지 했던 커히스토리아래 .
79
그림 28. 토픽 브랜치가 많음
를 처했던 방법 두 번째 방법iss91v2 브랜치가 괜찮아서 적용하기로 정했다. 이디어를 신할
수 없었던 dumbidea 브랜치를 이 일하는 다른 개발자에게 보여더니 괜찮다는 었다. iss91 브랜치는
(C5, C6 도 함) 고 다른 두 브랜치를 Merge 하면 아래 이 된다.
80
그림 29. dumbidea iss91v2 브랜치를 Merge 하고 난 후의 모습
환경에서의 Git에서 프로젝트를 Git으로 관리할 때 브랜치를 이용하여 만들 수 있는 여러 크플로에 대해 살펴.
관련 부분을 살펴보면 프로젝트에 어떤 형태용할수 있을 지 것이다.
지금까지 한 작은 전부 로에서만 처한다는 것을 하자. 소에서만 브랜치를 만들고 Merge 했으며
서버와 통신을 주고는 일은 없었다.
81
리모트 브랜치
모트 Refs모트 저소에 있는 포인터인 런스다. 모트 저소에 있는 브랜, , 등등을 의한다. git
ls-remote [remote] 명령으로 모든 모트 Refs회할 수 있다. git remote show [remote] 명령은 모든
모트 브랜그 정보를 보여. 모트 Refs가 있지만 보모트 트브랜치를 사용한다.
모트 트브랜치는 모트 브랜치를 추적하는 런스이며 브랜치다. 모트 트브랜치는 로에 있지만
의로 움일 수 없다. 모트 서버에 연결할 때마다 모트의 브랜데이트 내용에 따라서 자동으로 신될 뿐이다.
모트 트브랜치는 일마크라고 할 수 있다. 모트 저소에 마지으로 연결했던 순간에 브랜치가 무
을 가키고 있었는지를 나타.
모트 트브랜치의 이름은 <remote>/<branch> 형식으로 되어 있다. 예를 들어 모트 저origin
master 브랜치를 보고 다면 origin/master 라는 이름으로 브랜치를 인하면 된다. 다른 팀원과 함
구현할 때 그 팀원이 iss53 브랜치를 서버로 Push 했고 당신도 로iss53 브랜치가 있다고 가정하자. 이때 서버의
iss53 브랜치가 가키는 커은 로에서 `origin/iss53`이 가키는 커이다.
다소 갈릴 수 있으니 예제를 좀 더 살펴보자. git.ourcompany.com 이라는 Git 서버가 있고 이 서버의 저소를
하나 Clone 하면 Git은 자동으로 origin 이라는 이름을 인다. origin 으로부터 저소 데이터를 모내려
master 브랜치를 가키는 포인터를 만든다. 이 포인터는 origin/master 라고 부대로 할 수 없다.
Git은 로master 브랜치가 origin/master 를 가키게 한다. 이제 이 master 브랜치에서 작
시작할 수 있다.
“origin” 의 의미
브랜치 이름으로 많이 사용하는 “master” 라는 이름이 히 특한 의를 가지는 게 것처럼
“origin” 도 특한 의가 있는 것은 니다. git init 명령이 자동으로 만들기 때문에 사용하는
이름인 “master” 가지로 “origin” git clone 명령이 자동으로 만들어주는 모트
이름이다. git clone -o booyah 라고 옵션을 주고 명령을 실하면 booyah/master 라고
사용자가 정한 대로 모트 이름을 생성해.
82
그림 30. Clone 이후 서버와 로컬의 master 브랜치
소에서 어을 하고 있는데 동시에 다른 팀원이 git.ourcompany.com 서버에 Push 하고 master
브랜치를 데이트한다. 그러면 이제 팀원 간의 히스토리는 서로 달라. 서버 저소로부터 어데이터도 주고
origin/master 포인터는 그대로다.
83
그림 31. 로컬과 서버의 커밋 히스토리는 독립적임
모트 서버로부터 저소 정보를 동기하려면 git fetch origin 명령을 사용한다. 명령을 실하면 우
“origin” 서버의 주소 정보(이 예에서는 git.ourcompany.com)찾아, 재 로의 저소가 고 있지 않은
새로운 정보가 있으면 모내려, 은 데이터를 로소에 데이트하고 나서, origin/master 포인터의 위치를
신 커으로 이동시.
84
그림 32. git fetch 명령은 리모트 브랜치 정보를 업데이트
모트 저소를 여러 개 운영하는 상을 이해할 수 있도록 개발용으로 사용할 Git 소를 팀 내부에 하나 추가해 보자.
이 저소의 주소가 git.team1.ourcompany.com 이며 Git의 기에서 살펴git remote add 명령으로
중인 프로젝트에 팀의 저소를 추가한다. 이름을 teamone 으로 서버 주소 대신 사용한다.
85
그림 33. 서버를 리모트 저장소로 추가
서버를 추가하고 나면 git fetch teamone 명령으로 teamone 서버의 데이터를 내려는다. 명령을 실해도
teamone 서버의 데이터는 모origin 서버에도 있는 것들이라서 무것도 내려지 않는다. 하지만, 이 명령은
모트 트브랜teamone/master teamone 서버의 master 브랜치가 가키는 커을 가키게 한다.
86
그림 34. teamone/master 의 리모트 트래킹 브랜치
Push 하기
브랜치를 서버로 전송하려면 쓰기 한이 있는 모트 저소에 Push 한다. 소의 브랜치는
자동으로 모트 저소로 전송되지 않는다. 명시적으로 브랜치를 Push 정보가 전송된다. 따라서 모트 저소에
전송하지 않고 로컬 브랜치에만 는 비브랜치를 만들 수 있다. 또 다른 사람과 협업하기 위해 토픽 브랜치만 전송할
수도 있다.
serverfix 라는 브랜치를 다른 사람과 유할 때도 브랜치를 처음 Push 하는 것과 방법으로 Push 한다. 아래와
git push <remote> <branch> 명령을 사용한다.
87
$ git push origin serverfix
Counting objects: 24, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done.
Total 24 (delta 2), reused 0 (delta 0)
To https://github.com/schacon/simplegit
Ê* [new branch] serverfix -> serverfix
Gitserverfix라는 브랜치 이름을 refs/heads/serverfix:refs/heads/serverfix 확장한다. 이것은
serverfix 라는 로컬 브랜치를 서버로 Push 하는데 모트의 serverfix 브랜치로 데이트한다는 것을 의한다.
나중에 Git의 내부에서 refs/heads/ 을 자세히 알볼 것이기 때문에 일넘어가도록 한다. git push
origin serverfix:serverfix 라고 Push 하는 것도 은 의인데 이것은 serverfix 브랜치를 모트
소의 serverfix 브랜치로 Push 하라라는 이다. 컬 브랜치의 이름과 모트 서버의 브랜치 이름이 다를 때
요하다. 모트 저소에 serverfix 라는 이름 대신 다른 이름을 사용하려면 git push origin
serverfix:awesomebranch 처럼 사용한다.
암호를 매번 입력하지 않아도 된다
HTTPS URL로 시작하는 모트 저소를 사용한다면 마도 Push Pull을 할 때 인을 위한
사용자이름이나 호를 는 것을 볼 수 있다. 에서 작하는 경우 Git이 이 정보를
사용자로부터 기 위해 사용자이름이나 호를 입력받아 서버로 전달해서 한을 인한다.
모트에 접할 때마다 매번 사용자이름나 호를 입력하지 않도록 “credential cache
이용할 수 있다. 이 기을 활성하면 Git분 동입력한 사용자이름이나 호를 저.
을 활성하려면 git config --global credential.helper cache 명령을
하여 환경정을 추가한다.
이 기이 제하는 다른 옵션에 대한 자세한 명은 Credential 를 참고한다.
나중에 가 저소를 Fetch 하고 나서 서버에 있는 serverfix 브랜치에 접할 때 origin/serverfix 라는
이름으로 접할 수 있다.
$ git fetch origin
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/schacon/simplegit
Ê* [new branch] serverfix -> origin/serverfix
여기서 고 넘어가할 게 있다. Fetch 명령으로 모트 트브랜치를 내려는다고 해서 로소에 수정할 수
있는 브랜치가 새로 생기는 것이 니다. 다시 해서 serverfix 라는 브랜치가 생기는 것이 니라 그저 수정 못 하는
origin/serverfix 브랜치 포인터가 생기는 것이다.
새로 브랜치의 내용을 Merge 하려면 git merge origin/serverfix 명령을 사용한다. Merge 하지 않고
88
모트 트브랜치에서 시작하는 새 브랜치를 만들려면 아래와 같은 명령을 사용한다.
$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
그러면 origin/serverfix 에서 시작하고 수정할 수 있는 serverfix 라는 로컬 브랜치가 만들어.
브랜치 추적
모트 트브랜치를 로컬 브랜치로 Checkout 하면 자동으로 (Tracking) 브랜가 만들어(
하는 대상 브랜치를 “Upstream 브랜라고 부른다). 브랜치는 모트 브랜와 직접적인 연결가 있는 로
브랜치이다. 브랜치에서 git pull 명령을 내모트 저소로부터 데이터를 내려받아 연결모트
브랜자동으로 Merge 한다.
서버로부터 저소를 Clone을 하면 Git은 자동으로 master 브랜치를 origin/master 브랜치의 트브랜치로
만든다. 브랜치를 접 만들 수 있는데 모트를 origin 다른 모트로 할 수도 있고, 브랜치도 master
다른 브랜치로 추적하게 할 수 있다. git checkout -b <branch> <remote>/<branch> 명령으로
히 트브랜치를 만들 수 있다. --track 옵션을 사용하여 로컬 브랜치 이름을 자동으로 생성할 수 있다.
$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
이 명령은 우 자주 쓰여서 더 생할 수 있다. 입력한 브랜치가 있는 (a) 모트가 하나 있고 (b) 에는 없으면
Git은 트브랜치를 만들어 .
$ git checkout serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
모트 브랜다른 이름으로 브랜치를 만들려면 로컬 브랜치의 이름을 아래와 같이 다게 지정한다.
$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'
이제 sf 브랜치에서 Push Pull 하면 자동으로 origin/serverfix 로 데이터를 보내거나 가온다.
에 존재하는 브랜치가 모트의 특정 브랜치를 추적하게 하려면 git branch 명령에 -u --set
-upstream-to 옵션여서 아래와 같정한다.
89
$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Upstream 별명
추적 브랜치를 정했다면 추적 브랜치 이름을 @{upstream} 이나 @{u} 게 대하여 사용할
수 있다. master 브랜치가 origin/master 브랜치를 추적하는 경우라면 git merge
origin/master 명령과 git merge @{u} 명령을 똑같이 사용할 수 있다.
추적 브랜치가 재 어떻게 정되어 있는지 인하려면 git branch 명령에 -vv 옵션을 더한다. 이 명령을 실하면
컬 브랜치 목록과 로컬 브랜치가 추적하고 있는 모트 브랜치도 함보여. 게다가, 컬 브랜치가 서가는지
뒤쳐지는지에 대한 내용도 보여.
$ git branch -vv
Ê iss53 7e424c3 [origin/iss53: ahead 2] forgot the brackets
Ê master 1ae2a45 [origin/master] deploying index fix
* serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this
should do it
Ê testing 5ea463a trying something new
위의 과를 보면 iss53 브랜치는 origin/iss53 모트 브랜치를 추적하고 있다는 것을 알 수 있고 “ahead” 시를
해 로컬 브랜치가 커2서 있다(모트 브랜치에는 없는 커이 로에는 존재)는 것을 알 수 있다. master
브랜치는 origin/master 브랜치를 추적하고 있으며 두 브랜치가 가키는 커내용이 은 상이다. 컬 브랜치 중
serverfix 브랜치는 server-fix-good 이라는 teamone 모트 서버의 브랜치를 추적하고 있으며 커3
있으며 동시에 커1개로 뒤쳐있다. serverfix 브랜치에 서버로 보내지 않은 커3, 서버의
브랜치에서 아직 컬 브랜치로 지하지 않은 커1개 있다는 이다. 마지testing 브랜치는 추적하는 브랜치가
없는 상이다.
여기서 중요한 은 명령을 실했을 때 나타나는 과는 모마지으로 서버에서 데이터를 가(fetch)
으로 계한다는 이다. 순히 이 명령만으로는 서버의 신 데이터를 영하지는 않으며 로에 저된 서버의
시 데이터를 사용한다. 재 시에서 신 데이터로 추적 상을 알보려면 저 서버로부터 신 데이터를
받아온 후에 추적 상인해한다. 아래처럼 명령을 이어서 사용하는 것이 적당하다 하.
$ git fetch --all; git branch -vv
Pull 하기
git fetch 명령을 실하면 서버에는 존재하지만, 에는 아직 없는 데이터를 받아와서 저한다. 이 때
렉토리일 내용은 경되지 않고 그대로 는다. 서버로부터 데이터를 가져와서 저고 사용자가 Merge
하도록 비만 해. 하면 git pull 명령은 대부분 git fetch 명령을 실하고 나서 자동으로 git
merge 명령을 수하는 것 뿐이다. 바로 절에서 살펴대로 clone 이나 checkout 명령을 실하여 추적 브랜치가
정되면 git pull 명령은 서버로부터 데이터를 가져와재 로컬 브랜서버의 추적 브랜치를 Merge 한다.
90
적으로 fetch merge 명령을 명시적으로 사용하는 것이 pull 명령으로 한을 하는 것보다 .
리모트 브랜치 삭제
료와 협업하기 위해 모트 브랜치를 만들었다가 작을 마치고 master 브랜치로 Merge 했다. 협업하는 데 사용했던
모트 브랜치는 이제 더 이상 요하지 않기에 제할 수 있다. git push 명령에 --delete 옵션을 사용하여
모트 브랜치를 제할 수 있다. serverfix 라는 모트 브랜치를 제하려면 아래와 같이 실한다.
$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
Ê- [deleted] serverfix
위 명령을 실하면 서버에서 브랜(을 가키는 포인터) 하나가 사라. 서버에서 가비지 컬렉터가 동작하지
않는 한 데이터는 사라지지 않기 때문에 종종 의도치 않게 제한 경우에도 커한 데이터를 살수 있다.
Rebase 하기
Git에서 한 브랜치에서 다른 브랜치로 합치는 방법으로는 가지가 있다. 하나는 Merge 이고 다른 하나는 Rebase .
절에서는 Rebase가 무엇인지, 어떻게 사용하는지, 좋은 , 에서 사용하고 어에서 사용하지
말아야 하는지 알아 본.
Rebase 의 기초
Merge 의 기 절에서 살펴예제로 다시 돌아가 보자. 개의 나진 브랜치의 모습을 볼 수 있다.
91
그림 35. 두 개의 브랜치로 나누어진 커밋 히스토리
두 브랜치를 합치는 가방법에서 살펴대로 merge 명령을 사용하는 것이다. 두 브랜치의 마지밋 두
(C3, C4)와 공통 조(C2)을 사용하는 3-way Merge로 새로운 커을 만들어 .
그림 36. 나뉜 브랜치를 Merge 하기
과를 만드는 다른 방식으로, C3 에서 경된 사Patch로 만들고 이를 다시 C4 에 적용시키는 방법이 있다.
Git에서는 이런 방식Rebase 라고 한다. rebase 명령으로 한 브랜치에서 경된 사을 다른 브랜치에 적용할 수
있다.
위의 예제는 아래와 같은 명령으로 Rebase 한다.
92
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
실제로 일어나는 일을 명하자면 일단 두 브랜치가 나기 전인 공통 으로 이동하고 나서 그 커부터 지금
Checkout 브랜치가 가키는 커까지 diff차례로 만들어 어가에 시로 저해 놓는다. Rebase 브랜(
- experiment)가 합칠 브랜(- master)가 가키는 커을 가키게 하고 까 저해 놓았던 경사
차례대로 적용한다.
그림 37. `C4`의 변경사항을 `C3`에 적용하는 Rebase 과정
고 나서 master 브랜치를 Fast-forward .
$ git checkout master
$ git merge experiment
그림 38. master 브랜치를 Fast-forward시키기
C4' 시된 커에서의 내용은 Merge 예제에서 살펴C5 에서의 내용과 을 것이다. Merge 이든 Rebase
둘 다 합치는 관점에서는 서로 다를 게 없다. 하지만, Rebase가 좀 더 깨끗한 히스토리를 만든다. Rebase 브랜치의
Log를 살펴보면 히스토리선형이다. 일을 로 동시에 진행해도 Rebase 하고 나면 모든 작차례대로 수
것처럼 보인다.
Rebase는 보통 리모트 브랜치에 커깔끔하게 적용하고 을 때 사용한다. 마 이Rebase 하는 모트 브랜치는
93
관리하는 것이 니라 그참여하는 브랜치일 것이다. 인 프로젝트에 Patch를 보비가 되면 하는 것이
Rebase 니까 브랜치에서 하던 일을 전히 마치고 origin/master Rebase 한다. Rebase 하고 나면
프로젝트 관리자는 어합작요 없다. master 브랜치를 Fast-forward 시키면 된다.
Rebase를 하든지, Merge를 하든지 고 커히스토리만 다다는 것이 중요하다. Rebase 의 경우는
브랜치의 경사을 순서대로 다른 브랜치에 적용하면서 합치고 Merge 의 경우는 두 브랜치의 과만을 가지고
.
Rebase 활용
Rebase순히 브랜치를 합치는 것만 니라 다른 용도로도 사용할 수 있다. 다른 토픽 브랜치에서 나온 토픽
브랜 은 히스토리가 있다고 하자. server 브랜치를 만들어서 서버 기을 추가하고 그 브랜치에서 다시 client
브랜치를 만들어 라이트 기을 추가한다. 마지으로 server 브랜치로 돌아가서 가지 기을 더 추가한다.
그림 39. 다른 토픽 브랜치에서 갈라져 나온 토픽 브랜치
이때 스트가 server 브랜치는 그대로 client 브랜치만 master 로 합치려는 상을 생각해보자.
server 관련이 없는 client C8, C9 이다. master 브랜치에 적용하기 위해서 --onto
옵션을 사용하여 아래와 같은 명령을 실한다:
$ git rebase --onto master server client
이 명령은 master 브랜치부터 server 브랜client 브랜치의 공통 조상까지의 커client 브랜치에서
을 때 사용한다. client 브랜치에서만 경된 치를 만들어 master 브랜치에서 client 브랜치를 기으로
새로 만들어 적용한다. 복잡해도 쓸모 있다.
94
그림 40. 다른 토픽 브랜치에서 갈라져 나온 토픽 브랜치를 Rebase 하기
이제 master 브랜치로 돌아가서 Fast-forward 수 있다(master 브랜치를 client 브랜치 위치로 진행 시키기 참고).
$ git checkout master
$ git merge client
그림 41. master 브랜치를 client 브랜치 위치로 진행 시키기
server 브랜치의 일이 다 나면 git rebase <basebranch> <topicbranch> 라는 명령으로 Checkout 하지
않고 바로 server 브랜치를 master 브랜치로 Rebase 할 수 있다. 이 명령은 토픽(server) 브랜치를 Checkout 하고
이스(master) 브랜치에 Rebase 한다.
$ git rebase master server
server 브랜치의 수정사master 브랜치에 적용했다. 과는 master 브랜치에 server 브랜치의 수정 사을 적용
.
95
그림 42. master 브랜치에 server 브랜치의 수정 사항을 적용
고 나서 master 브랜치를 Fast-forward .
$ git checkout master
$ git merge server
모든 것이 master 브랜치에 합됐기 때문에 더 요하지 않다면 client server 브랜치는 제해도 된다.
브랜치를 제해도 커히스토리히스토리 이 여전히 남아 있다.
$ git branch -d client
$ git branch -d server
그림 43. 최종 커밋 히스토리
Rebase 의 위험성
Rebase장점이 많은 기이지만 단점이 없는 것은 니니 심해한다. 그 주의사아래 한 문으로 표현할 수
있다.
이미 공개 저장소에 Push 한 커밋을 Rebase 하지 마라
이 지만 지키면 Rebase를 하는 데 문제 될 게 없다. 하지만, 이 주의사을 지키지 않으면 사람들에게 을 것이다.
Rebase는 기존의 커을 그대로 사용하는 것이 니라 내용은 지만 다른 커을 새로 만든다. 새 커을 서버에 Push
하고 동가가 그 커Pull 해서 작을 한다고 하자. 그런데 그 커git rebase 로 바Push
해버면 동가 다시 Push 했을 때 동는 다시 Merge 한다. 고 동가 다시 Merge 한 내용을 Pull 하면 내
코드는 정엉망이 된다.
미 공개 저소에 Push 한 커Rebase 하면 어떤 결과가 되는지 예제를 해 알보자. 소에서 Clone
하고 일부 수정을 하면 커히스토리아래와 같아 진.
96
그림 44. 저장소를 Clone 하고 일부 수정함
이제 팀원 중 가 커, Merge 하고 나서 서버에 Push 한다. 모트 브랜치를 Fetch, Merge 하면 히스토리
아래와 같이 된다.
97
그림 45. Fetch 한 후 Merge
그런데 Push 했던 팀원은 Merge 한 일을 되돌리고 다시 Rebase 한다. 서버의 히스토리를 새로 우려면 git
push --force 명령을 사용해한다. 이후에 저소에서 Fetch 하고 나면 아래 은 상가 된다.
98
그림 46. 한 팀원이 다른 팀원이 의존하는 커밋을 없애고 Rebase 한 커밋을 다시 Push
자 이게 되면 짬뽕이 된다. git pull 로 서버의 내용을 가져와Merge 하면 은 내용의 수정사을 포함한 Merge
아래와 같이 만들어.
그림 47. 같은 Merge를 다시 한다
99
git log 로 히스토리인해보면 저자, 밋 날, 시지가 은 커개 있다(C4, C4'). 게 되면
. 게다가 이 히스토리를 서버에 Push 하면 은 커개 있기 때문에 다른 사람들도 스러한다.
`C4``C6`는 포함되지 았어할 커이다. 애초에 서버로 데이터를 보내기 전에 Rebase로 커을 정했어
했다.
Rebase 한 것을 다시 Rebase 하기
이런 상질 때 유용한 Git 이 하나 있다. 팀원이 제로 내가 한일을 다고 하자. 그러면 내가
했던 일이 무엇이고 내용이 무엇인지 알한다.
SHA 외에도 Git은 커Patch 할 내용으로 SHA-1 을 한한다. “patch-id” 라고
한다.
받아서 그 커을 기으로 Rebase 할 때 Git은 원래 누가 작성한 코드인지 잘 찾아 낸. Patch
대로 적용된다.
예를 들어 서 살펴예제를 보면 한 팀원이 다른 팀원이 의존하는 커을 없Rebase 한 커을 다시 Push
에서 Merge 하는 대신 git rebase teamone/master 명령을 실하면 Git아래와 같은 작을 한다.
브랜치에만 포함된 커정한다. (C2, C3, C4, C6, C7)
Merge 것을 정한다. (C2, C3, C4)
이 중 merge브랜치에 어쓰이지 않은 커정한다. (C2, C3. C4C4’동일한 Patch)
정한 커teamone/master 브랜치에 적용한다.
과를 인해보면 Merge를 다시 한다 과 대신 제대로 정제로 쓴 브랜치에 Rebase 하기
과를 을 수 있다.
그림 48. 강제로 덮어쓴 브랜치에 Rebase 하기
100
가 생성했던 C4C4' 내용이 전히 을 때만 이게 동작된다. 내용이 예 다거나 비하다면 커
개 생(은 내용이 두 번 될 수 있기 때문에 깔끔하지 않다).
git pull 명령을 실할 때 옵션여서 git pull --rebase Rebase 할 수도 있다. 물론 git fetch
git rebase teamone/master 명령을 접 순서대로 실해도 된다.
git pull 명령을 실할 때 기적으로 --rebase 옵션이 적용되도록 pull.rebase 정을 추가할 수 있다. git
config --global pull.rebase true 명령으로 추가한다.
Push 하기 전에 정하려고 Rebase 하는 것은 괜찮. 또 절대 개하지 않고 Rebase 하는 경우도 괜찮. 하지만,
미 공개하여 사람들이 사용하는 커Rebase 하면 틀림없이 문제가 생.
나중에 후회하지 git pull --rebase 로 문제를 미리 방지할 수 있다는 것을 이 작하는 동료와
유하기 바.
Rebase vs. Merge
Merge, Rebase지 여러 예제를 해 간히 살펴보았다. 지금이런 의문이 들 거로 생각한다. 둘 중 무엇을
쓰는 게 좋지? 이 질문에 대한 기 전에 히스토리의 의에 대해서 잠깐 다시 생각해보자.
히스토리를 보는 관점 중에 하나는 작업한 내용의 기록으로 보는 것이 있다. 내용을 기록한 문서이고, 각 기록은 각각
를 가지며, 경할 수 없다. 이런 관점에서 커히스토리경한다는 것은 사를 부정하는 이 된다. 제 무
일이 있었는지 기록에 대해 거짓말 을 하게 되는 것이다. 게 했을 때 지저분하게 수많은 Merge 이 히스토리
게 되면 문제가 없을까? 역사는 후세를 위해 기록하고 보존해한다.
히스토리프로젝트가 어떻게 진행되었나에 대한 이야기로도 볼 수 있다. 소프트어를 주의 게 편하는 방법
뉴얼이나 세세한 작내용을 벌부터 개하고 지 않을 수 있다. 나중에 다른 사람에게 들려주기 좋도록 Rebase
filter-branch 은 도로 프로젝트의 진행 기를 다으면 좋다.
Merge Rebase 중 무엇이 나으는 질문은 다시 생각해이 그치 않다. Git력한 도고 기
서 히스토리을 수 있지만, 모든 팀과 모든 이가 처한 상은 모. 예제를 Merge Rebase
무엇이고 어인지 배. 이 둘을 어떻게 쓸지는 각자의 상과 각자의 판에 달렸다.
적인 해이 드자면 로컬 브랜치에서 작할 때는 히스토리를 정하기 위해서 Rebase 할 수도 있지만,
모트 등 어가에 Push로 내보에 대해서는 절대 Rebase 하지 말아야 한다.
요약
는 이 에서 Git으로 브랜치를 만들고 Merge 의 기적인 사용을 다루었다. 이제 브랜치를 만들고 옮겨다니고
Merge 하는 것에 을 것으로 생각한다. 브랜치를 Rebase 해서 Push 해서 유하는 것 정도는 어렵지 않게 할 수
있을 것이다. 다음 에서는 Git 소 서버를 접 운영하는 방법명한다.
101
Git 서버
자라면 이하루 무의 대부분을 Git으로 처할 수 있을 거라고 생각한다. 이제는 다른 사람과 협업하는
방법을 고민해보자. 다른 사람과 협업하려면 모트 저소가 요하다. 물론 자서 저소를 만들고 거기에 Push 하고
Pull 할 수도 있지만 이게 하는 것은 무 의가 없다. 이런 방식으로는 다른 사람이 무일을 하고 있는지 알려면
보고 있어간신히 알 수 있을 터이다. 당신이 오프라인일 때도 동가 저소를 사용할 수 있게 하려면 제나
이용할 수 있는 저소가 요하다. , 동으로 사용할 수 있는 저소를 만들고 모이 저소에 접하여 Push, Pull
할 수 있어한다.
Git 서버를 운영하는 우 간하다. 사용할 전송 프로토콜부터 정한다. 부분에서는 어프로토콜
있는지 그고 각 장단점은 무엇인지 살펴. 그다음각 프로토콜을 사용하는 방법과 그 프로토콜을 사용할 수 있도록
서버를 성하는 방법을 살펴. 마지으로 다른 사람의 서버에 내 코드를 싫고 고생스게 서버를 치하고
관리하고 지도 않을 때 고를 수 있는 선택지가 어것들이 있는지 살펴.
서버를 치해서 운영할 생각이 없으면 이 의 마지절만 어도 된다. 마지절에서는 Git 호스팅 서비스에
계정을 만들고 사용하는 방법에 대해 명한다. 고 다음 에서는 분환경에서 소스를 관리하는 다에 대해
의할 것이다.
모트 저소는 일적으로 렉토리가 없는 Bare 저장소 이다. 이 저소는 협업용이기 때문에 아웃
없다. Git 데이터만 있으면 된다. 다시 해서 Bare 소는 일프로젝트에서 .git 렉토리만 있는 저소다.
프로토콜
GitLocal, HTTP, SSH, Git 가지의 프로토콜을 사용할 수 있다. 이 절에서는 각각 어경우에 유용한지
살펴.
로컬 프로토콜
적인 것이 로컬 프로토콜 이다. 모트 저소가 순히 은 시스의 다른 디렉토리에 있을 때 사용한다.
팀원들이 전부 한 시스에 로그인하여 개발하거나 니면 NFS은 것으로 일시스유하고 있을 때 사용한다.
이런 상은 문제가 될 수 있다. 모든 저소가 한 시스에 있기 때문에 한순간에 모두 잃을 수 있다.
일시스을 마운트했을 때는 로소를 사용하는 것처럼 Clone 하고 Push 하고 Pull 하면 된다.
소를 Clone 하거나 프로젝트에 모트 저소로 추가한다. 추가할 때 URL 에 저소의 경로를 사용한다. 예를
들어 아래와 같이 로소를 Clone 한다.
$ git clone /srv/git/project.git
아래처럼도 가하다:
$ git clone file:///srv/git/project.git
102
Git일 경로를 접 쓸 때file:// 로 시작하는 URL을 사용할 때를 간 다게 처한다. 렉토리 경로를
그대로 사용하면 Git요한 일을 사하거나 하드 크를 사용한다. 하지만 file:// 로 시작하면 Git
크를 해서 데이터를 전송할 때처럼 프로세스를 도로 생성하여 처한다. 이 프로세스로 데이터를 전송하는
것은 효율이 좀 어지지만 그file:// 를 사용하는 이유가 있다. 이것은 외부 Refs나 개들이 포함된 저소의
깨끗한 상고자 함이다. 은 다른 버전 관리 시스들에서 포트한 후에 사용한다(Git의 내부에서
자세히 다). 여기서는 속도가 른 디렉토리 경로를 사용한다.
Git 프로젝트에는 아래와 같이 로소를 추가한다.
$ git remote add local_proj /srv/git/project.git
그러면 크에 있는 모트 저소처럼 local_proj 이름으로 모트처럼 Push 하거나 Pull 할 수 있다.
장점
일 기소의 장점은 간하다는 것이다. 기존에 있던 크나 일의 한을 그대로 사용하기 때문에 정하기
쉽다. 팀 전가 접할 수 있는 일시스을 가지고 있다면 저소를 주 쉽게 성할 수 있다. 다른 디렉토리
유할 때처럼 모든 동고 쓸 수 있는 유 디렉토리Bare 소를 만들면 된다. 다음 절인 서버에 Git
치하기에서 Bare 소를 만드는 방법을 살펴볼 것이다.
또한, 가 작하는 저소에서 한 일을 바로 가오기에도 좋다. 프로젝트를 하는 동가 자신이 한 일을
당신이 인해 으면 한다. git pull /home/john/project 처럼 명령어를 실우 쉽게 동
코드를 가져올 수 있다. 그 동가 서버에 Push 하고 당신이 다시 Pull 요 없다.
단점
한 상에서 접할 수 있도록 디렉토리유하는 것 자가 일적으로 어렵다. 에 있을 때 Push 하면
모트 저소가 있는 디스크를 마운트해하는데 이것은 다른 프로토콜을 이용하는 방법보다 느고 어렵다.
게다가 일시스을 마운트해서 사용하는 중이라면 빠르지도 않다. 소는 데이터를 빠르을 수 있을
때만 빠르. NFS에 있는 저소에 Git을 사용하는 것은 보통 같은 서버에 SSH로 접하는 것보다 느.
마지으로 이 프로토콜은 저소에 우발적인 사고가 발생하지 않도록 보호해주지 않는다. 모든 사용자는 에서
모트렉토리에 무슨 짓이든지 할 수 있다. 가 저소에 해서 Git 내부 일을 제하고 경하지 못하도록
하는 치가 없다.
HTTP 프로토콜
GitHTTP신할 때, 서로 다른 두 방법으로 HTTP를 사용할 수 있다. 1.6.6 이전 버전에서는 기만 가순한
방법에 사용할 수 없었다. 1.6.6 버전부터는 똑똑한 프로토콜을 사용할 수 있다. 이 프로토콜Git 데이터를 전송할 때
SSH처럼 서로 상한다. 새로운 HTTP 프로토콜은 사용이 쉽고 기도 좋서 많은 사람들이 사용하고 있다.
프로토콜을 보스마트 HTTP 프로토콜이라 하고 예전의 HTTP 프로토콜멍청한 HTTP 프로토콜이라고 한다.
스마트 HTTP 프로토콜명한다.
스마트 HTTP
103
스마트 HTTP 프로토콜SSHGit 프로토콜처럼 신한다. 다만 HTTPHTTPS 포트를 이용해 신하고 다
HTTP 방식을 사용한다는 것이 다. SSH는 키를 발하고 관리하는 거로움이 있지만, HTTP
사용자이름과 호만으로 인할 수 있기 때문에 더 편하게 사용할 수 있다.
마 지금은 Git에서 가많이 사용하는 프로토콜일 것이다. git:// 프로토콜처럼 명으로 사용할 수도 있고,
SSH처럼 인을 거Push 할 수도 있기 때문이다. 가지 동작을 다른 URL로 나요없이 하나의 URL
합해서 사용할 수 있다. 놓은 저소에 Push를 하면 서버는 사용자이름과 호를 .
FetchPull 기 작에서도 URL을 사용한다.
실제로 GitHub 은 서비스에서 제하는 저소는 Clone을 할 때나 Push를 할 때 URL을 사용한다. (,
https://github.com/schacon/simplegit)
멍청한 HTTP
Git 서버가 스마트 HTTP 응답하지 않으면 Git 라이트는 차선책으로 멍청한 HTTP 프로토콜을 시도한다.
멍청한 프로토콜은 원소를 그냥 파주는 웹 서버로 한다. HTTPHTTPS 프로토콜름다정도로
정이 간하다. HTTP 트 루트 Bare 소를 post-update 정하는 것이 기적으로 해
하는 일의 전부다(Git Hooks 에서 자세히 다것이다). 소가 있는 웹 서버에 접할 수 있다면 그 저소를 Clone
수도 있다. 아래와 같HTTP해서 저소를 을 수 있게 한다.
$ cd /var/www/htdocs/
$ git clone --bare /path/to/git_project gitproject.git
$ cd gitproject.git
$ mv hooks/post-update.sample hooks/post-update
$ chmod a+x hooks/post-update
다 됐다. post-update Git에 포함되어 있으며 git update-server-info 라는 명령어를 실.
명령어를 써HTTPFetchClone 명령이 제대로 동작한다. SSH해서 저소에 Push 하면 post-
update 이 실된다. 그럼 다른 사용자들은 Push 일을 아래와 같Clone 할 수 있다.
$ git clone https://example.com/gitproject.git
여기서는 Apache 서버를 사용해서 기루트 디렉토리/var/www/htdocs 를 사용하지만 다른 웹 서버를 사용해도
된다. 순히 Bare 소를 HTTP 문서 루트에 으면 된다. Git 데이터는 일적인 정적 일처럼 된다(Git의 내부
에서 정히 어떻게 처하는지 다).
은 스마트 HTTP 프로토콜만 이용하거나 멍청HTTP 프로토콜만 사용한다. 이 둘을 한꺼번에 사용하는 경우는
.
장점
스마트 HTTP 프로토콜장점만 보자
쓰기에 하나의 URL만 사용한다. 고 사용자에게 한 사용자이름과 방식의 인을 사용한다.
사용자이름과 방식의 인SSH에 비해 사용하기 간하다. SSH는 사용자가 알서 키를 만들고 개키를 서버에
104
올린 후에비로소 인을 수 있다. SSH에 대해 거나 지 않은 사용자를 생각하면 이런 사용성은 엄청
장점이다. 게다가 SSH만큼이나 빠르고 효율적이기 까지 하다.
HTTPS를 이용해서 전송하는 데이터를 하는 것도, 라이트에게 서명된 SSL 서를 요하는 것도 가하다.
HTTPS우 보편적인 프로토콜이기 때문에 거의 모든 회사 방화에서 과하도록 있다는 장점도 있다.
단점
HTTPS를 사용하도록 정하는 것이 SSH정하는 것보다 까다로운 서버가 있다. 그것 고는 스마트 HTTP
프로토콜이 다른 프로토콜보다 못한 단점로 없다.
Push 할 때 HTTP 을 사용하면 SSH 키를 사용하는 것보다 좀 더 복잡하다. 도 인증 캐싱 툴을 사용하면 좀
. OSX에는 키(Keychain Access), Windows에는 인관리(Credential Manager)가 있다. HTTP
캐싱 정에 대한 더 자세한 사Credential 를 참고하.
SSH 프로토콜
Git의 대프로토콜SSH이다. SSH를 이용하면 무런 외부 도없이 Git 서버를 구축할 수 있다. 대부분 서버는
SSH로 접할 수 있도록 있다. , 있지 않더라도 쉽게 정할 수 있다. SSH는 인이 있고
어디에서든 사용할 수 있으며 사용하기도 쉽다.
SSHGit 소를 Clone 하려면 ssh:// 로 시작하는 URL을 사용한다:
$ git clone ssh://[user@]server/project.git
아래와 같SCP 형태문으로 여 쓸 수도 있다.
$ git clone [user@]server:project.git
사용자 계정을 생할 수도 있는데 계정을 생하면 Git재 로그인한 사용자의 계정을 사용한다.
장점
SSH 장점은 정많다. , SSH는 상대적으로 정하기 쉽다. SSH 은 정하다. 많은 관리자들은
SSH 을 다루어 이 있고 대부분의 OS 배포판에는 SSH 관리들이 모들어 있다. , SSH
해 접하면 보전하다. 모든 데이터는 되어 인된 상로 전송된다. 마지으로 SSHHTTPS, Local
프로토콜과 마가지로 전송 시 데이터를 가하기 때문에 효율적이다.
단점
SSH명으로 접할 수 없다. 심지어 기 전용인 경우에도 명으로 시스에 접할 수 없다. 회사에서만 사용할
거라면 SSH가 가적합한 프로토콜일 것이지만 오픈소스 프로젝트는 SSH만으로는 부하다. SSH를 사용하는
프로젝트에 명으로 접할 수 있게 하려면, Push 할 때는 SSH로 하고 다른 사람들이 Fetch 할 때는 다른 프로토콜
사용하도록 정해한다.
105
Git 프로토콜
Git 프로토콜Git에 포함된 데을 사용하는 것이다. 포트는 9418이며 SSH 프로토콜과 비한 서비스를 제하지만,
커니이 없다. 소에 git-export-daemon-ok 일을 만들면 Git 프로토콜로 서비스할 수 있지만,
없다. 일이 없는 저소는 서비스되지 않는다. 이 저소는 누구Clone 할 수 있거나 무도 Clone 할 수 없거나 둘
중의 하나만 선택할 수 있다. 서 이 프로토콜로는 Push 하게 할 수 없다. 하자면 Push 할 수 있도록 정할
수 있지만, 하도록 할 수 없다. 그러니까 당신이 Push 할 수 있으면 이 프로젝트의 URL는 사람은 누구Push
수 있다. 이런 것도 있지만 잘 안 쓴다고 알고 있으면 된다.
장점
Git 프로토콜은 전송 속도가 가장 빠르다고 할 수 있다. 전송이 많은 개 프로젝트나 도의 인요 없고 기만
용하는 프로젝트를 서비스할 때 유용하다. 화와 을 빼면 SSH 프로토콜과 전송 커니별반 지 않다.
단점
Git 프로토콜단점은 인커니이 없다는 것이다. Git 프로토콜만으로 접할 수 있는 프로젝트는 바람하지
못하다. 적으로 SSHHTTPS 프로토콜과 함사용한다. 소수의 개발자만 Push 할 수 있고 대다수 사람은 git://
을 사용하여 을 수만 있게 하는 것이다. 면 가장 설치하기 어려운 방법일 수도 있다. 도의 데요하고
프로젝트에 정해한다. 자원을 수 있도록 xinetd 은 것도 정해하고 방화과할 수 있도록 9418
포트도 열어한다. 이 포트는 일적으로 회사들이 용하는 표준 포트가 니다. 모가 회사의 방화이라면 당
이 포트를 막아 놓는다.
서버에 Git 설치하기
서버에 Git치해서 개하는 방법을 알보자.
여기에서는 Linux치하는 방법에 대해서만 간명할 것이다. 물론 MacWindows에도
치할 수 있다. 실제로 서버에 Git치하고 정하려면 온안 조치를 정하고 OS 들을
한다. 그 모든 것을 이 에서 다루않지만 무엇에 신경 써하는지는 알 수 있을 것이다.
서버를 치하더라도 일소를 Bare 소로 만들어한다. 다시 하지만, Bare 소는 렉토리
없는 저소이다. --bare 옵션을 주고 Clone 하면 새로운 Bare 소가 만들어. Bare 소 디렉토리관례
따라 .git 자가 이름에 는다.
$ git clone --bare my_project my_project.git
Cloning into bare repository 'my_project.git'...
done.
이제 my_project.git 렉토리에는 사한 Git 렉토리 데이터만 들어 있다.
아래와 같이 실한 것과 비하다:
106
$ cp -Rf my_project/.git my_project.git
물론 설정상의 세한 이가 있지만, 소의 내용만 고려한다면 다고 볼 수 있다. 렉토리가 없는 Git 소인
데다가 도의 디렉토리도 하나 만들었다는 에서는 .
서버에 Bare 저장소 넣기
Bare 소는 이제 만들었으니까 서버에 고 프로토콜정한다. git.example.com 라는 이름의 서버를 하나
비하자. 고 그 서버에 SSH로 접속할 수 있게 만들고 Git 소를 /srv/git 렉토리에 저할 것이다. 서버에
/srv/git 렉토리가 있다고 가정하고 아래와 같Bare 소를 사한다.
$ scp -r my_project.git user@git.example.com:/srv/git
이제 다른 사용자들은 SSH로 서버에 접해서 저소를 Clone 할 수 있다. 사용자는 /srv/git 렉토리한이
있어한다.
$ git clone user@git.example.com:/srv/git/my_project.git
이 서버에 SSH로 접할 수 있는 사용자가 /srv/git/my_project.git 렉토리에 쓰기 한까지 가지고 있으면
바로 Push 할 수 있다.
git init 명령에 --shared 옵션을 추가하면 Git은 자동으로 그쓰기 한을 추가한다.
$ ssh user@git.example.com
$ cd /srv/git/my_project.git
$ git init --bare --shared
Git 소를 만드는 것이 마나 운지 살펴보았다. Bare 소를 만들어 SSH로 접할 수 있는 서버에 올리면 동료와
일할 비가 난다.
그러니까 Git 서버를 구축하는데 사람이 할 일은 정말 별로 없다. SSH로 접속할 수 있도록 서버에 계정을 만들고 Bare
소를 사람들이 고 쓸 수 있는 기만 하면 된다. 이제 비됐다. 요한 것은 없다.
다음 절에서는 좀 더 정하게 정하는 을 살펴볼 것이다. 사용자에게 계정을 만들어 주는 , 소를 고 쓸 수 있게
하는 , UI정하는 등은 여기에서 명하지 않는다. 료와 개발할 때 요한 것은 SSH 서버Bare
소뿐이라는 것만은 하자.
초 간단 뚝딱
약 창업비하고 있거나 회사에서 Git도입하려고 할 때는 개발자의 수가 많지 않정할 게 로 없다.
사용자를 관리하는 것이 Git 서버를 정할 때 가장 골픈 것 중 하나다. 사람이 많으면 어사용자는 기만 가하게
하고 어사용자는 고 쓰기 둘 다 가하게 해한다. 정하는 것은 금 더 까다.
107
SSH 접속
모든 개발자가 SSH로 접속할 수 있는 서버가 있으면 무 쉽게 저소를 만들 수 있다. 이 정할 일이
로 없다. 고 저소의 한을 꼼꼼하게 관리하면 운영제의 일시스관리를 이용할 수 있다.
가 저소에 쓰기 접을 해하는 데 아직 SSH로 접속할 수 있는 서버가 없으면 하나 마한다. 마 당신에게
서버가 하나 있다면 그 서버에는 이SSH 서버가 치되어 있고 지금도 SSH로 접속하고 있을 것이다.
팀원들이 접속할 수 있도록 하는 방법가지가 있다. 로 모에게 계정을 만들어 주는 방법이 있다. 방법이 제일
순하지만 다소 . 팀원마다 adduser 를 실시키고 호를 부여해하기 때문에 보방법을 쓰고
하지 않는다.
로 서버마다 'git’이라는 계정을 하나만드는 방법이 있다. 쓰기 한이 요한 사용자의 SSH 개키를 모
'git' 계정의 ~/.ssh/authorized_keys 일에 모든 키를 입력한다. 그러면 모'git' 계정으로 그 서버에 접속할 수
있다. 'git' 계정은 커데이터에는 무런 영치지 않는다. 다시 해서 접속하는 데 사용한 SSH 계정과 커
되는 사용자는 무 상없다.
SSH 서버 인LDAP 서버를 이용할 수도 있다. 사용하고 있는 중앙집소스가 있으면 해당 인
이용하여 SSH 서버에 인하도록 할 수도 있다. SSH 커니무거나 하나 이용할 수 있으면 사용자는 그
서버에 접할 수 있다.
SSH 공개키 만들기
많은 Git 서버들은 SSH 개키로 인한다. 개키를 사용하려면 일단 공개키를 만들어한다. 개키를 만드는 방법
모든 운영제가 비하다. 저 키가 있는지부터 인하자. 사용자의 SSH 키들은 기적으로 사용자의 ~/.ssh
렉토리에 저한다. 서 만렉토리일을 살펴보면 이미 공개키가 있는지 인할 수 있다.
$ cd ~/.ssh
$ ls
authorized_keys2 id_dsa known_hosts
config id_dsa.pub
id_dsaid_rsa라는 일 이름이 보일 것이고 이에 일명의 .pub 라는 확장자가 일이 하나 더 있을
것이다. 그중 .pub 일이 개키이고 다른 일은 개인키다. 일들이 없거나 .ssh 렉토리도 없으면 ssh-
keygen 이라는 프로그으로 키를 생성해한다. ssh-keygen 프로그LinuxMacSSH 키지에 포함
있고 Windows'Git for Windows' 에 들어 있다.
108
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/schacon/.ssh/id_rsa):
Created directory '/home/schacon/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/schacon/.ssh/id_rsa.
Your public key has been saved in /home/schacon/.ssh/id_rsa.pub.
The key fingerprint is:
d0:82:24:8e:d7:f1:bb:9b:33:53:96:93:49:da:9b:e3 schacon@mylaptop.local
.ssh/id_rsa 키를 저하고 은 디렉토리를 입력하고 호를 두 번 입력한다. 이때 호를 비워두면 키를 사용할 때
호를 지 않는다.
다음은 사용자가 자신의 개키를 Git 서버 관리자에게 보내한다. 사용자는 .pub 일의 내용을 사하여 이일을
보내기만 하면 된다. 개키는 아래와 같이 생.
$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFi9wrf+M7Q== schacon@mylaptop.local
다른 운영 제에서 SSH 키를 만드는 방법금하면 https://help.github.com/articles/generating-ssh-keys
있는 GitHub 명서를 찾아보는 게 좋다.
서버 설정하기
서버에서 정하는 일을 살펴보자. Ubuntu표준 Linux 배포판을 사용한다고 가정한다. 사용자들은 마도
authorized_keys 일로 인할 것이다.
ssh-copy-id 명령을 사용하면 여기에서 명하는 SSH 개키를 사하고 치하는 내용을
자동한 도이다.
git 계정을 만들고 사용자 렉토리.ssh 렉토리를 만든다:
$ sudo adduser git
$ su git
$ cd
$ mkdir .ssh && chmod 700 .ssh
$ touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys
109
authorized_keys 일에 SSH 개키를 추가해사용자가 접할 수 있다. 추가하기 전에 이알고 있는 사람의
개키를 받아서 가지고 있다고 가정한다. 개키가 어떻게 생는지 다시 한번 확인하자.
$ cat /tmp/id_rsa.john.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4L
ojG6rs6hPB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4k
Yjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9Ez
Sdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myiv
O7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPq
dAv8JggJICUvax2T9va5 gsg-keypair
.ssh 렉토리에 있는 authorized_keys 일에 추가한다:
$ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys
$ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys
$ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys
--bare 옵션을 주고 git init 를 실해서 렉토리가 없는 소를 하나 만든다.
$ cd /srv/git
$ mkdir project.git
$ cd project.git
$ git init --bare
Initialized empty Git repository in /srv/git/project.git/
이제 John, Josie, Jessica는 이 저소를 모트 저소로 등록하고 나서 브랜치를 Push 할 수 있다. 프로젝트마다
적어도 한 명은 서버에 접속해서 Bare 소를 만들어한다. git 계정과 저소를 만든 서버의 호스트 이름이
gitserver 라고 하자. 이 서버가 내부에 있고 gitserver 가 그 서버를 가키도록 DNS정하면 아래와
은 명령을 사용할 수 있다(myproject 프로젝트가 이있다고 가정한다).
# on John's computer
$ cd myproject
$ git init
$ git add .
$ git commit -m 'initial commit'
$ git remote add origin git@gitserver:/srv/git/project.git
$ git push origin master
이제 이 프로젝트를 Clone 하고 나서 수정하고 Push 할 수 있다.
110
$ git clone git@gitserver:/srv/git/project.git
$ cd project
$ vim README
$ git commit -am 'fix for the README file'
$ git push origin master
게 개발자들이 고 쓸 수 있는 Git 서버를 쉽게 만들 수 있다.
이 개발자들은 서버에 git 계정으로 로그인할 수 있다. 이를 으려면 passwd 일에서 로그인 을 바한다.
순히 로그인 git-shell 로 바기만 하면 git 계정으로는 git 만 사용할 수 있다. 이 로그인 은 서버의 다른
부분은 들 수 없도록 있다. git-shell 을 사용자의 로그인 로 지정해한다. /etc/shells git-shell
추가한다. 아래를 보자.
$ cat /etc/shells # `git-shell` 등록 있는지
$ which git-shell # git-shell 행파일이 있는지
$ sudo vim /etc/shells # 바로 명령으로 인한 git-shell 행파일의 절대경로를
추가
chsh <계정이름> -s <shell> 명령어를 이용해서 특정 계정의 을 바수 있다.
$ sudo chsh git # git-shell 경로를 입력, /usr/bin/git-shell
이제 git 계정으로 Push Pull 할 수 있지만 서버의 은 가질 수 없다. 로그인하려고 하면 아래와 같이 로그인
시지만 보게 될 것이다.
$ ssh git@gitserver
fatal: Interactive git shell is not enabled.
hint: ~/git-shell-commands should exist and have read and execute access.
Connection to gitserver closed.
이제 Git은 제대로 동작하면서 개발자들이 지 못하게 되었다. 위의 출력에서 볼 수 있git 계정의
렉토리git-shell-commands 렉토리를 만들어 git-shell 의 동작을 금 바수 있다. 예를 들면 서버에서
사용할 수 있는 Git 명령어를 제한할 수 있다. 또 명령어를 실했을 때 나오는 시지도 경 할 수 있다. git help
shell 명령어를 실하면 Git 는 데에 요한 정보를 을 수 있다.
Git 데몬
여기“Git” 프로토콜로 동작하는 데방법을 알아본. 방법은 인이 없는 Git 소를 만들 수 있는
장 빠방법이다. 다시 한 번 강조하지만, 이 없다. 전 세계 누구든지 데이터에 접할 수 있다는 이다.
111
서버가 외부에 그노출있다면 우선 방화으로 보호하고 프로젝트를 외부에서 접할 수 있게 만들어한다.
고 이서버를 방화으로 보호하고 있어도 사람이나 컴퓨(CI 서버나 드 서버)기 접을 할 수 있도록 SSH
키를 일일이 추가하고 지 않을 것이다.
Git 프로토콜은 상대적으로 치하기 쉽다. 을 실하면 된다.
$ git daemon --reuseaddr --base-path=/srv/git/ /srv/git/
--reuseaddr 는 서버가 기존의 연결이 타임아웃될 때까지 기다고 바로 재시작하게 하는 옵션이다. --base
-path 옵션을 사용하면 사람들이 프로젝트를 Clone 할 때 전경로를 사용하지 않도 된다. 고 마지에 있는
경로는 노출할 저소의 위치를 Git 에 알려주는 것이다. 마지으로 방화을 사용하고 있으면 9418 포트를 열어서
지금 작하는 서버의 주어한다.
운영제에 따라 Git 을 실시키는 방법은 다.
대개의 스 배포판은 systemd` 보편적으로 사용하며 이를 이용하는 방법 적이다.
아래 내용으로 `/etc/systemd/system/git-daemon.service 일을 작성한다.
[Unit]
Description=Start Git Daemon
[Service]
ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/srv/git/ /srv/git/
Restart=always
RestartSec=500ms
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=git-daemon
User=git
Group=git
[Install]
WantedBy=multi-user.target
여기서 주의해서 할 부분은 git 이라는 사용자을 사용하여 Git 이 실된다는 이다. 운영하는 환경에
따라 이 부분을 이존재하는 사용자나 그을 지정해서 사용할 수도 있다. 위의 예제에서는 Git 행 파일의 위치가
/usr/bin/git 으로 정되어 있으나 다른에 위치해있다면 경해주어한다.
마지으로 systemctl enable git-daemon 명령을 실해서 시스이 부팅될 때 자동으로 서비스가 시작되고,
시스될 때 자동으로 서비스도 되도록 정한다. systemctl start git-daemon, systemctl
stop git-daemon 명령으로도 정할 수 있다.
우분LTS 14.04 까지는 Upstart 성을 사용한다. 따라서 14.04 이하의 버전이라면 Upstart 스크트를 사용한다.
112
선 아래와 같일을 만든다.
/etc/init/local-git-daemon.conf
아래의 내용을 입력한다.
start on startup
stop on shutdown
exec /usr/bin/git daemon \
Ê --user=git --group=git \
Ê --reuseaddr \
Ê --base-path=/srv/git/ \
Ê /srv/git/
respawn
을 위해서 저소를 을 수만 있는 사용자로 데을 실것을 력하게 고한다. git-ro 라는 계정을 새로
만들고 그 계정으로 데을 실시키는 것이 좋다. 하지만 여기에서는 쉽게 명하려고 git-shell` 하는
동일한 사용자인 `git 계정을 사용한다.
서버가 재시작할 때 Git 이 자동으로 실되고 데어도 자동으로 재시작될 것이다. 서버는 Git
재시작할 수 있다.
$ initctl start local-git-daemon
다른 시스에서는 sysvinit 시스xinetd 스크트를 사용하거나 자신만의 방법으로 해한다.
무나 을 수 있다는 것을 Git 서버에 알려주어한다. 소에 git-daemon-export-ok 일을 만들면 된다.
$ cd /path/to/project.git
$ touch git-daemon-export-ok
일이 있으면 Git 은 인없이 프로젝트를 노출하는 것으로 판한다.
스마트 HTTP
지금까지 인SSH이 없는 git 프로토콜을 배. 이제는 이 을 한꺼번에 가
프로토콜을 알보자. 서버에서 git-http-backend 명령어를 이용해 일적인 스마트 HTTP를 지원하는 Git
서버를 실한다. Git 라이트에서 git fetch git push 를 실하면 서버로 HTTP 을 보. 서버는 그
을 보고 경로더를 라이트가 HTTP신하려 하는지 지한다. 이는 1.6.6 버전 이상의
라이트에서 동작한다. 서버는 라이트가 스마트 HTTP 프로토콜을 지원한다고 판되면 스마트 HTTP
프로토콜을 사용하고 니면 멍청한 프로토콜을 계속 사용한다. 분에 하위 호환성이 유지된다.
113
이제 정해보자. CGI 서버로 Apache를 사용한다. Apache가 없다면 Linux에서는 아래와 같Apache치할 수
있다 .
$ sudo apt-get install apache2 apache2-utils
$ a2enmod cgi alias env
이 명령어 한 이면 mod_cgi, mod_alias, mod_env 도 사용할 수 있다. 으로 사용할 모들이다.
/srv/git 렉토리Unix 사용자 그www-data 정해한다. 래야 웹 서버가 저소를 고 쓸 수 있다.
Apache 인스스는 CGI 스크트를 이 사용자로 실(본 설정이다).
$ chgrp -R www-data /srv/git
Apache 일을 수정한다. 그러면 git http-backend 를 실했을 때 모든 요/git 경로로 을 수
있다.
SetEnv GIT_PROJECT_ROOT /srv/git
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/
GIT_HTTP_EXPORT_ALL 환경 수를 정하지 않으면 git-daemon-export-ok 일이 있는 저소에는 무나
다 접할 수 있게 된다. Git 의 동작과 똑같.
마지으로 Apachegit-http-backend 에 요하는 것을 용하고 쓰기 접시 인하게 한다.
<Files "git-http-backend">
Ê AuthType Basic
Ê AuthName "Git Access"
Ê AuthUserFile /srv/git/.htpasswd
Ê Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*'
|| %{REQUEST_URI} =~ m#/git-receive-pack$#)
Ê Require valid-user
</Files>
.htpasswd 일에는 접가하려는 사용자의 호가 들어가 있어한다. 아래“schacon” 사용자를
추가하는 방법이다.
$ htpasswd -c /srv/git/.htpasswd schacon
Apache에는 사용자 인방법이 많다. 그중 하나를 라 사용해하는데 위에 명한 방법이 가방법의 하나다.
고 이게 사용자 인정을 할 때는 보을 위해 SSL로 접속해 작하는 것이 좋다.
114
웹 서버는 Apache 고도 다른 서버를 사용할 수도 있고, 방식도 다르므Apache 정에 대해서 게 이기하지
않는다. 대신 이것만 알아두었으면 한다. HTTP를 이용한 모든 신에서는 git http-backend Git을 함
사용한다는 것이다. Git 그 자로는 인을 가지고 있지 않다. 하지만 웹 서버의 인이어와 손쉽게 동할 수
있다. CGI를 실할 수 있는 웹 서버라면 어서버든지 일 수 있다. 하는 서버를 사용하.
Apache 웹 서버에서 인정에 대해 더 자세히 알보려면 Apache 문서를 참고하.
(http://httpd.apache.org/docs/current/howto/auth.html)
GitWeb
프로젝트 저소를 순히 거나 쓰는 것에 대한 정은 다. 이제는 웹 기인터이스를 정해 보자. Git은 웹에서
소를 회할 수 있는 GitWeb이라는 CGI 스크트를 제한다.
그림 49. Git 웹용 UI, GitWeb
GitGitWeb을 쉽게 사용해 볼 수 있도록 서버를 우는 명령을 제한다. 시스lighttpd webrick
웹 서버가 있어이 명령을 사용할 수 있다. Linux에서는 lighttpd 를 많이 사용한다. lighttpd
있으면 프로젝트 디렉토리에서 그git instaweb 을 실하면 바로 실될 것이다. MacLeopard 버전은
Ruby미리 설있기 때문에 webrick 이 더 나은 선택이다. 사용할 웹 서버가 lighttpd 니라면 아래와 같
--httpd 옵션을 사용해한다.
115
$ git instaweb --httpd=webrick
[2009-02-21 10:02:21] INFO WEBrick 1.3.1
[2009-02-21 10:02:21] INFO ruby 1.8.6 (2008-03-03) [universal-darwin9.0]
게 하면 1234 포트로 HTTPD 서버를 시작하고 이 이지를 여는 웹 라우저를 자동으로 실. 사용자에게는
하다. 요한 일을 모마치고 나서 은 명령어에 --stop 옵션을 추가하여 서버를 중지한다:
$ git instaweb --httpd=webrick --stop
자신의 프로젝트에서 제나 웹 인터이스를 운영하려면 저 웹 서버에 이 CGI 스크트를 치해한다. 몇몇 리
배포판에서는 apt dnf 으로 치할 수 있게 gitweb 키지를 제한다. 그러니 키지로 치할 수 있는지 인해
보는 것이 좋다. 여기에서는 GitWeb을 수동으로 치하는 방법을 간히 살펴보자. GitWeb이 포함된 Git 소스
코드를 한 다음 아래CGI 스크트를 드한다.
$ git clone git://git.kernel.org/pub/scm/git/git.git
$ cd git/
$ make GITWEB_PROJECTROOT="/srv/git" prefix=/usr gitweb
Ê SUBDIR gitweb
Ê SUBDIR ../
make[2]: `GIT-VERSION-FILE' is up to date.
Ê GEN gitweb.cgi
Ê GEN static/gitweb.js
$ sudo cp -Rf gitweb /var/www/
드할 때 GITWEB_PROJECTROOT 수로 Git 소의 위치를 알려. 이제 Apache가 이 스크트를 사용하도록
VirtualHost 목에 정한다.
<VirtualHost *:80>
Ê ServerName gitserver
Ê DocumentRoot /var/www/gitweb
Ê <Directory /var/www/gitweb>
Ê Options +ExecCGI +FollowSymLinks +SymLinksIfOwnerMatch
Ê AllowOverride All
Ê order allow,deny
Ê Allow from all
Ê AddHandler cgi-script cgi
Ê DirectoryIndex gitweb.cgi
Ê </Directory>
</VirtualHost>
다시 해서 GitWebCGIPerl을 지원하는 웹 서버라면 무거나 사용할 수 있다. 이제 http://gitserver/
접속하여 온라인으로 저소를 인할 수 있다.
116
GitLab
하게 쓰기GitWeb좋다. 그런데 좀 더 기이 많은 Git 서버를 쓰려면 다른 서버를 찾아 설치해한다.
GitLab사용하는 서버 중 하나이다. 여기서 예제를 치하고 사용하는 것을 배보자. GitLab은 기이 많은
만큼 정도 복잡하고 유지보수를 위해 해할 것도 많다.
설치
GitLab은 데이터이스따로 동해하는 웹 이라 다른 Git 서버들보다 치하기에 복잡하지만,
문서되어있으로 이를 참고한다.
방법은 여러 가지가 있다. 가상 신 이지나 원인스러를 내려받아 리 설치하고 환경에 게 후다
정해서 사용할 수 있다. https://bitnami.com/stack/gitlab에서 내려을 수 있다. Bitnami의 로그인 면은 아래와
(alt-러서 들어간다). 로그인 면에 치된 GitLabIP사용자이름, 호가 써있다.
그림 50. Bitnami GitLab 가상 머신의 로그인 화면
더 많은 것이 알고 다면 GitLab 커뮤니티 에디readme 일을 어보면 된다. https://gitlab.com/gitlab-org/
gitlab-ce/tree/master에서 내려을 수 있다. ChefDigital Ocean(- 호스팅 서비스)의 가상 ,
RPM, DEB 키지 등에 방법들이 있다. “공식적인명서도 있다. 치 않은 운영제나 데이터이스
동하는 , 스크트로 전히 수동으로 치하는 등 많은 주제를 다.
관리자
GitLab관리자 도는 웹 이지로 되어있다. 라우저로 GitLab치된 의 주소에 들어가면 그보인다.
관리자로 로그인하자. 사용자이름은 admin@local.host, 호는 5iveL!fe 이다(로그인 후에 바
117
수 있다). 로그인하고 나서 오른위에 있는 “Admin area” 한다.
그림 51. GitLab 메뉴의 “Admin area” 버튼
사용자
GitLab의 사용자 계정은 한 사람당 하나만든다. 사용자 계정의 내용은 복잡하지 않다. 로그인 데이터에 추가로 개인
정보가 들어있다. 각 사용자마다 네임스페이스가 있다. 네임이스는 프로젝트를 위이다. jane 사용자가
project라는 프로젝트를 진행 중이라면 프로젝트의 URL`http://server/jane/project`가 될 것이다.
그림 52. GitLab 사용자의 관리 화면
사용자를 제하는 방법가지다. 일시적으로 GitLab에 로그인하지 못하게 하는 정지(Blocking)” 가 있다. 정지한
사용자 데이터와 네임이스 의 프로젝트 데이터는 제되지 않고 그대로 는다. 의 이일 주소에 대한 크도
여전히 사용자 프로이지로 연결된다.
하지만 사용자를 (Destroying)” 하면 그 사용자와 관련된 모든 데이터가 제된다. 제한 사용자의 모든
프로젝트데이터가 제되고 해당 사용자가 소유한 그제된다. 돌릴 수 없으심해한다.
그룹
GitLab 은 프로젝트와 누가 어프로젝트에 어떻게 접할지에 대한 한 데이터의 모음이다. 에도 사용자처럼
118
프로젝트 네임이스가 있다. +training+라는 그+materials+라는 프로젝트를 가지고 있으면 URL
`http://server/training/materials`가 된다.
그림 53. GitLab의 그룹 관리 화면
은 많은 사용자가 모인 이다. 의 사용자의 한은 그의 프로젝트에 대한 한과 그에 대한 한이 따로
있다. 한은 “Guest”(등록과 팅만 할 수 있다.)부터 “Owner”(, 프로젝트에 대한 모든 제어가
하다.)까지 지정할 수 있다. 여기에서 어한이 있는지 나열하기무 많다. GitLab관리 화면에서 각 한에
대한 크를 참고하.
프로젝트
GitLab의 프로젝트는 간히 이기하면 하나의 Git 소다. 모든 프로젝트는 한 사용자나 한 그에 속하게 된다.
사용자에 프로젝트는 사용자가 관리자로서 그 프로젝트를 전히 제어한다. 프로젝트는 해당 그
사용자 에 따라 다.
프로젝트마다 개 수을 지정할 수 있어서 사람마다 프로젝트 이지소가 보이거나 보이게 할 수 있다.
프로젝트가 Private 이면 프로젝트 소유자가 한 사람들만 프로젝트에 접할 수 있다. Internal 은 로그인한
사용자에게만 보인다. Public 프로젝트는 모든 사람이 볼 수 있다. 이런 개 수git fetch 은 접이나
UI 에 다 적용된다.
GitLab도 지원하는데 프로젝트 이나 시스템 훅을 사용할 수 있다. 은 어트가 발생하면 해당 이
정보가 담긴 JSON 데이터를 HTTP POST로 보. Git 소나 GitLab동해서 CI, 개발 도등으로
자동하기에 좋다.
119
기본 사용법
저 새로운 프로젝트를 만들어보자. 바의 “+” 한다. 프로젝트의 이름, 프로젝트 네임이스,
을 입력한다. 지금 입력한 것은 대부분 나중에 다시 바수 있다. “Create Project” 하면 난다.
프로젝트가 만들어으면 로Git 랑 연결하자. HTTPSSSH 프로토콜을 이용해 프로젝트를 Git 모트로
등록한다. URL은 프로젝트 이지 위 에 있다. 아래와 같이 명령어를 이용해 로소에 gitlab 이라는
이름으로 모트 저소를 등록한다.
$ git remote add gitlab https://server/namespace/project.git
소가 없으면 그냥 아래 명령어를 실한다.
$ git clone https://server/namespace/project.git
UI유용하다. 소에 대한 각정보를 보여. 프로젝트 이지에서는 최근 활동을 보여주고 제일 위의
크를 하면 프로젝트의 일과 커로그가 나온다.
함께 일하기
일할 사람에게 그Git 소의 Push 한을 주는 걸로 간하게 협업을 시작할 수 있다. 프로젝트
이지에서 “Members” 섹션이 일할 사용자를 추가한다. 고 그 사용자가 Push 할 수 있도록 정한다(다른
에 대해서는 에서 볼 수 있다). “Developer” 이상의 한을 주면 그 사용자는 우소에 Push 하거나
브랜치를 만들 수 있다.
Merge 을 하도록 해서 을 유지한 협업하는 방법도 있다. 프로젝트에 접할 수 있는 모든 사용자가
프로젝트에 기여할 수 있다. 사용자는 마음브랜치를 만들고 커, Push 하고 나서 이 브랜치를 master 나 다른
브랜치에 Merge 해달라고 요한다. Push 한이 없는 사용자는 저소를 “fork한 다음에 “fork자신의 저장소
Push 한다. 고는 원소에 내 저소에 있는 브랜치를 Merge 해달라고 요하면 된다. 소유자는 이걸로 자신의
소에 대한 모든 한을 가. 데이터가 들어수 있는지 제 들어오는지 소유자가 정할 수 있다.
Merge 과 이는 대의 기본 단위이다. Merge 에서는 일적인 토론뿐만 니라 라인 위로까지 대
이루어. 물론 코드 가 간수도 있다. 과 이는 모사용자에게 할당되거나 마일스의 과제로
편입된다.
섹션에서는 GitLabGit은 부분만 명했지만 이게 전부가 니다. GitLab히 성했다. 이 외에도
프로젝트 위키나 토론“walls”, 시스템 관리 협업용 기이 많다. GitLab장점은 일서버가 돌아가면
SSH로 서버에 접속할 일이 로 없다는 것이다. 대부분 관리는 웹 라우저로 가하다.
또 다른 선택지, 호스팅
Git 서버를 접 운영하기가 부스러수 있다. 그런 사람들을 위해 Git 호스팅 서비스가 가지 있다. 외부 Git 호스팅
서비스를 사용하면 좋은 이 있다. 정이 쉽고 서버 관리 비용을 수 있다. 내부적으로 Git 서버를 운영하더라도 소스
코드를 개하기 위해 호스팅 서비스를 이용해할 수 있다. 이런 으로 쉽게 오픈 소스 커뮤니티를 성한다.
재 많은 호스팅 서비스가 있다. 각각 장단점이 있으잘 선택해서 사용하면 된다. https://git.wiki.kernel.org/
120
index.php/GitHostingGit 호스팅 서비스 스트가 있으니 참고하자.
GitHub에 대해서는 GitHub에서 자세히 명하려 한다. GitHub은 가장 큰 Git 호스팅 서비스이다. Git 서버를
운영하지 않으려면 수개의 호스팅 서비스 중에서 하나를 한다.
요약
Git 서버를 운영하거나 사람들과 협업을 하는 방법 몇 가지를 살펴 보았다.
자신의 서버에서 Git 서버를 운영하면 제어 위가 어지고 방화등을 운영할 수 있다. 하지만 정하고 유지보수하는
데에 시간이 많이 든다. 호스팅 서비스를 이용하면 정과 유지보수가 워진. 대신 코드를 외부에 게 된다. 자신의
회사나 조직에서 이를 용하는지 사용하기 전에 인해한다.
요에 따라 둘 중 하나를 선택하든지, 니면 두 방법을 적절히 어서 사용하는 것이 좋다.
121
분산 환경에서의 Git
에서 다른 개발자코드를 유하는 모트 저소를 만드는 을 배. 에서 작하는 데 요한 기적인
명령어에는 어느 정도 . 이제는 분환경에서 Git이 제하는 기을 어떻게 효율적으로 사용할지를 배운다.
번 장에서는 분환경에서 Git을 어떻게 사용할 수 있을지 살펴. 프로젝트 기여자 입과 여러 수정사
합하는 관리자 입에서 루 살펴. , 프로젝트 기여자 또는 관리자로서 작업물을 프로젝트에 어떻게
포함시수 많은 개발자가 수한 일을 합하고 프로젝트를 운영하는 방법을 배운다.
분산 환경에서의 워크플로
앙집버전 관리 시스과는 달Git은 분산형이다. Git구조우 유하기 때문에 여러 개발자가 함
하는 방식을 더 다하게 성할 수 있다. 앙집버전 관리 시스에서 각 개발자는 중소를 중심으로 하는
한 노드일 뿐이다. 하지만, Git에서는 각 개발자의 저소가 하나의 노드이기도 하고 중할도 할 수 있다.
, 모든 개발자는 다른 개발자의 저소에 일한 내용을 전송하거나, 다른 개발자들이 참여할 수 있도록 자신이 운영하는
소 위치를 개할 수도 있다. 이런 특은 프로젝트나 팀이 코드를 운영할 때 다크플로를 만들 수 있도록
. 이런 유성을 살려 저소를 운영하는 가지 방식을 소개한다. 방식장단점을 살펴보고 그 방식 중 하나를
거나 여러 가지를 적절히 어 쓰면 된다.
중앙집중식 워크플로
앙집시스에서는 보앙집식 협업 이라는 한 가지 방식에 없다. 소는 하나 있고
은 모이 중소에 중된다. 개발자는 이 중소를 중심으로 작한다
그림 54. 중앙집중식 워크플로.
122
앙집에서 개발자 명이 중소를 Clone 하고 각자 수정하는 상을 생각해보자. 한 개발자가 자신이 한 일을
하고 나서 무 문제 없이 서버에 Push 한다. 그러면 다른 개발자는 자신의 일을 커하고 Push 하기 전에 번째
개발자가 한 일을 Merge 한다. Merge를 해번째 개발자가 작한 내용을 어쓰지 않는다. 이런 개념은
Subversion은 중앙집버전 관리 시스에서 사용하는 방식이고 Git에서도 당히 이런 크플로를 사용할 수
있다.
팀이 작거나 이앙집에 적한 상이라면 이 크플로에 따라 Git을 도입하여 사용할 수 있다. 소를
하나 만들고 개발자 모에게 Push 한을 부여한다. 에게 Push 한을 부여해도 Git은 한 개발자가 다른 개발자의
내용을 어쓰도록 용하지 않는다. JohnJessica가 동시에 은 부분을 수정하는 상을 생각해보자. John
저 작내고 수정한 내용을 서버로 Push 한다. Jessica도 마가지로 작내고 수정한 내용을 서버로 Push
하려 하지만 서버가 바로 받아주지 않는다. 서버에는 John이 수정한 내용이 추가되었기 때문에 Push 하기 전에 Fetch
받아Merge 한 후 Push 할 수 있다. 이런 개념은 개발자에게 해서 거부없이 도입할 수 있다.
작은 팀만 이게 일할 수 있는 것이 니다. Git이 제하는 브랜관리 을 사용하면 수백명의 개발자가 한 프로젝트
에서 다브랜치를 만들어서 함하는 것도 쉽다.
Integration-Manager 워크플로
Git을 사용하면 모트 저소를 여러 개 운영할 수 있다. 다른 개발자는 기만 가하고 자신은 쓰기도 가
소를 만드는 크플로도 된다. Workflow에는 보프로젝트를 대하는 공식 소가 있다. 기여자는 우선 공식
소를 하나 Clone 하고 수정하고 나서 자신의 저소에 Push 한다. 그 다음에 프로젝트 Integration-Manager에게
새 저소에서 Pull 하라고 요한다. 그러면 그 Integration-Manager는 기여자의 저소를 모트 저소로 등록하고,
에서 기여스트하고, 프로젝트 브랜치에 Merge 하고, 그 내용을 다시 프로젝트 인 저소에 Push 한다.
이런 과정은 아래와 같(Integration-manager workflow.).
1. 프로젝트 Integration-Manager는 프로젝트 인 저소에 Push를 한다.
2. 프로젝트 기여자는 인 저소를 Clone 하고 수정한다.
3. 기여자는 자신의 저소에 Push 하고 Integration-Manager가 접할 수 있도록 개해 놓는다.
4. 기여자는 Integration-Manager에게 경사을 적용해 것을 이일로 요한다.
5. Integration-Manager는 기여자의 저소를 모트 저소로 등록하고 수정사Merge 하여 스트한다.
6. Integration-ManagerMerge 한 사인 저소에 Push 한다.
123
그림 55. Integration-manager workflow.
방식GitHubGitLab Hub 사이트를 해 주로 사용하는 방식이다. 프로젝트를 Fork 하고 수정사
영하여 다시 모에게 개하기 좋은 구조있다. 방식장점은 기여자Integration-Manager가 각자의
사정에 프로젝트를 유지할 수 있다는 이다. 기여자는 자신의 저와 브랜치에서 수정 작을 계속해 나수 있고
수정사이 프로젝트에 영되도록 기다릴 필요가 없다. 관리자는 여유를 가지고 기여자가 Push 해 놓은 커을 적절한
Merge 한다.
Dictator and Lieutenants 워크플로
방식은 저소를 여러개 운영하는 방식변형구조이다. 수백 명의 개발자가 참여하는 프로젝트를
운영할 때 이 방식을 사용한다. Linux 프로젝트가 대적이다. 여러 명의 Integration-Manager가 저소에서
자신이 은 부분만을 당하는데 이들을 Lieutenants 라고 부른다. 모든 Lieutenant관리아래에 있으며 이
관리자를 Benevolent Dictator 라고 부른다. Benevolent DictatorLieutenant의 저소를 가져와 공식
소에 Push 하고 모든 프로젝트 참여자는 이 공식 소에서 드시 Pull 한다. 이러한 크플로는 아래와 같
(Benevolent dictator workflow.).
1. 개발자는 코드를 수정하고 master 브랜치를 기으로 자신의 토픽 브랜치를 Rebase 한다. 여기서 master
브랜란 공식 소의 브랜치를 한다.
2. Lieutenant들은 개발자들의 수정사을 자신이 관리하는 master 브랜치에 Merge 한다.
3. DictatorLieutenantmaster 브랜치를 자신의 master 브랜치로 Merge 한다.
4. Dictator는 자신의 master 브랜치를 Push 하며 다른 모든 개발자는 Dictatormaster 브랜치를 기으로
Rebase 한다.
124
그림 56. Benevolent dictator workflow.
방식이 일적이지 않지만 은 계층 구조를 가지는 환경이나 모가 프로젝트에서는 우 쓸모 있다. 프로젝트
더가 모든 코드를 합하기 전에 코드를 부분부분 합하도록 여러 명의 Lieutenant에게 위한다.
워크플로 요약
이 세 가지 크플로가 Git 은 분버전 관리 시스에서 주로 사용하는 것들이다. 사실 이런 크플로뿐만 니라
크플로가 실제로 사용된다. 떤 방식선택하고 합해하는 지 살것이다. 으로
가지 구체적 사를 들고 우가 다한 환경에서 각 할을 어떻게 수하는지 살펴. 이어지는 내용에서 프로젝트에
참여하고 기여할 때 작업 패이 어한지 가지 살펴보기로 한다.
프로젝트에 기여하기
프로젝트에 기여하는 방식명하는데 가어려운 은 그 방식우 다하다는 이다. Git하게
계됐기 때문에 사람들은 여러 가지 방식으로 사용할 수 있다. 게다가 프로젝트마다 환경이 달라서 프로젝트에 기여하는
방식을 쉽게 명하기어렵다. 기여하는 방식에 영치는 가지 수가 있다. 활발히 기여하는 개발자의
수가 마인지, 선택크플로가 무엇인지, 각 개발자에게 접한을 어떻게 부여했는지, 외부에서도 기여할 수 있는지
등이 수다.
번째로 살펴볼 수는 활발히 활동하는 개발자의 수이다. 마나 많은 개발자가 마나 자주 코드를 내는가 하는
이 활발한 개발자의 기이다. 대부분 둘, 정도의 개발자가 하루에 몇 번 을 하고 활발하지 않은 프로젝트는 더
할 것이다. 하지만, 프로젝트는 수백, 수천 명의 개발자가 하루에도 수, 수백 개의 커을 만들어 .
개발자가 많으면 많을수록 코드를 깔끔하게 적용하거나 Merge 하기 어려워진. 은 다른 개발자가 이기여한
것으로 불필요해지기도 하고 때서로 이 일어난다. 어떻게 해코드를 신으로 유지하면서 원하는 대로 수정할 수
있을까?
두 번째 변수는 프로젝트에서 선택크플로다. 개발자 모인 저소에 쓰기 한을 는 중앙집형 방식인가?
125
프로젝트에 모든 Patch사하고 합하는 관리자가 따로 있는가? 모든 수정사을 개발자하고 인하는가?
자신이 그저 는게 니라 어고 있는지? 중간 관리자가 있어서 그들에게 저 알려하는가?
번째 변수는 접한이다. '프로젝트에 쓰기 한이 있어서 접 쓸 수 있는가? 니면 기만 가한가?'에 따라서
프로젝트에 기여하는 방식우 달라. 쓰기 한이 없다면 어떻게 수정 사을 프로젝트에 영할 수 있을까?
수정사을 적용하는 정책이 프로젝트에 있는가? 마나 많은 시간을 프로젝트에 할하는가? 마나 자주 기여하는가?
이런 질문에 따라 프로젝트에 기여하는 방법크플로가 달라. 한 것부터 복잡한 것까지 예제를 해 각 상
살펴보면 실제 프로젝트에 요한 크플로를 선택하는 데 도움이 될 것이다.
커밋 가이드라인
다른 것보다 저 커밋 메시지에 대한 주의사을 알보자. 밋 메시지를 작성하는 가이드라인을 알아두면 다른
개발자일하는 데 도움이 많이 된다. Git 프로젝트에 보면 커밋 메시지를 작성하는데 참고할 만한 좋은 이 많다.
Git 프로젝트의 Documentation/SubmittingPatches 문서를 참고하자.
무엇보다도 백문자를 깨끗하게 정하고 커한다. Git백문자를 사해볼 수 있는 간한 명령을
한다. 을 하기 전에 git diff --check 명령으로 백문자에 대한 오인할 수 있다.
그림 57. git diff --check 의 결과.
을 하기 전에 백문자에 대해 사를 하면 백으로 불필요하게 커되는 것을 고 이런 커으로 인해 불필요하게
다른 개발자들이 신경 쓰는 일을 지할 수 있다.
고 각 커논리적으로 분되는 Changeset이다. 대한 수정사을 한 주제로 요할 수 있어하고 여러 가지
에 대한 수정사을 하나의 커지 않아야 한다. 여러 가지 이를 한꺼번에 수정했다고 하더라도 Staging
Area를 이용하여 한 커에 이하나만 기도록 한다. 내용을 분할하고, 각 커마다 적절한 시지를 작성한다.
일의 다른 부분을 수정하는 경우에는 git add -patch 명령을 써서 한 부분Staging Area
한다(관련 내용은 화형 명령 에서 다). 과적으로 프로젝트의 모습은 한 에 커을 하든 다
126
어 커을 하든 똑같.
하지만, 여러 어 커하는 것이 다른 동가 수정한 부분을 인할 때나 각 커의 시으로 원해서 할 때
이해하기 훨씬 쉽다. 히스토리 단장하기 에서 이된 커을 다시 수정하거나 일을 계적으로 Staging Area
하는 방법을 살펴. 한 도를 이용해서 간하고 이해하기 운 커한다.
마지으로 명심해은 커밋 메시지 자. 좋은 커밋 메시지를 작성하는 습Git을 사용하는 데 도움이 많이
된다. 적으로 커밋 메시지를 작성할 때 사용하는 규칙이 있다. 시지의 라인에 50자가 넘지 않는 주 간
시지를 적어 해당 커을 요한다. 다음 한 라인은 비우고 그다음 라인부터 커을 자세히 명한다. 예를 들어 Git 개발
프로젝트에서는 개발 동기와 구현 의 제약 조이나 상등을 자세하게 요한다. 이런 은 따를 만한 좋은
가이드라인이다. 형 표현을 사용하는 것이 좋다. 명령문으로 시작하는 것도 좋은 방법이다. 예를 들어 “I
added tests for (스트를 추가함)” 보다는 “Add tests for (스트 추가)” 와 같시지를 작성한다. 아래 내용은 Tim
Pope가 작성한 커밋 메시지의 릿이다.
영문 50 이하의 수정
자세한 . 영문 72 이상이 되면
라인 하고 이어지는 내용을 작성한다.
특정 에서는 번째 라인이
시지의 제목이 되고 지는
내용이 된다. 라인은 문과
구별해주기에 중요하다( 하지 않는 ).
이어지는 내용도 라인 우고 .
Ê - 목록 시도 사용할 있다.
Ê - '-' '*' 시를 사용해서 목록을 표현하고
Ê 하나, 목록 사이에는 라인
Ê 하나를 는데, 따라 .
시지를 이게 작성하면 함일하는 사람은 물론이고 자신에게도 우 유용하다. Git 개발 프로젝트에는 쓰인 커
시지가 많으로 프로젝트를 내려받아git log --no-merges 명령으로 살펴보기를 한다.
책 처럼 하지말고, 시키는 대로 하기.
시간 계상, 이 책에서 명하는 예제의 커밋 메시지는 위와 같지게 쓰지 않았다. git
commit 명령에서 -m 옵션을 사용하여 간하게 적는다.
하지만! 저자처럼 하지 고 시키는 대로 하는 것이 좋다.
비공개 소규모 팀
세 명으로 이루어개 프로젝트가 가한 프로젝트일 것이다. “라고 함은 소스코드가 개되지 않은
것을 하는 것이지 외부에서 접할 수 없는 것을 하지 않는다. 모든 개발자는 유하는 저소에 쓰기 한이 있어
한다.
127
이런 환경에서는 보Subversion 은 중앙집버전 관리 시스에서 사용하던 방식을 사용한다. 물론 Git이 가
오프라인 커이나 브랜Merge 을 이용하하지만 크게 다지 않다. 장 큰 차은 서버가
라이에서 Merge 한다는 이다. 개발자가 저소를 유하는 시나오를 살펴보자. 개발자인 John
소를 Clone 하고 일을 수정하고 나서 로에 커한다 (예제에서 Git이 출력하는 시지 중 일부는 `…`으로
이고 생했다).
# John's Machine
$ git clone john@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'remove invalid default value'
[master 738ee87] remove invalid default value
Ê1 files changed, 1 insertions(+), 1 deletions(-)
개발자인 Jessica도 저소를 Clone 하고 나서 일을 하나 새로 추가하고 커한다.
# Jessica's Machine
$ git clone jessica@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'add reset task'
[master fbff5bc] add reset task
Ê1 files changed, 1 insertions(+), 0 deletions(-)
Jessica는 서버에 커Push 한다.
# Jessica's Machine
$ git push origin master
...
To jessica@githost:simplegit.git
Ê 1edee6b..fbff5bc master -> master
Push 명령을 실하고 난 과 중 가마지막 줄은 유용한 정보를 보여주고 있다. 마지막 줄의 기적인 형태
<oldref>..<newref> fromref toref 이다. `oldref`는 이전 런스를, `newref`는 새 런스를,
`fromref`Push 명령에서 사용한 로컬 레런스의 이름을, `toref`Push데이트한 모트 런스를
나타. 이어지는 내용에서 지금과 비Push 명령 출력 과는 여러한다. 이 출력 시지의 내용을 이해하고
있으면 다한 상에서 정하게 어일이 벌어지는가를 좀 더 쉽게 이해할 수 있다. 자세한 내용을 좀 더 살펴보려면 Git
문서 git-push를 참고한다.
다시 예제 내용으로 돌아오면, John도 내용을 경하고 커을 만든 후 서버로 커Push 하려고 한다.
128
# John's Machine
$ git push origin master
To john@githost:simplegit.git
Ê! [rejected] master -> master (non-fast forward)
error: failed to push some refs to 'john@githost:simplegit.git'
JessicaPush한 내용으로 인해, John의 커은 서버에서 거절된다. Subversion을 사용했던 사람은 이 부분을
이해하는 것이 중요하다. 일을 수정한 것도 Push가 거절되는 걸까? Subversion에서는 서로 다른
일을 수정하는 이런 Merge 은 자동으로 서버가 처한다. 하지만 Git은 로에서 Merge 한다. 다시
JohnPush 하기 전에 Jessica가 수정한 커Fetch 하고 Merge 한다는 이다.
이를 위해 우JohnJessica의 작내용을 아래와 같Fetch 한다(아래 명령은 Jessica의 작내용을 내려받긴
하지만 Merge 까지 하지는 않는 작이다).
$ git fetch origin
...
From john@githost:simplegit
Ê+ 049d078...fbff5bc master -> origin/master
Fetch 하고 나면 John의 로소는 아래와 같이 된다.
그림 58. Fetch 하고 난 John의 저장소.
이제 JohnFetch하여 가Jessica의 작내용을 Merge 할 수 있다.
129
$ git merge origin/master
Merge made by the 'recursive' strategy.
ÊTODO | 1 +
Ê1 files changed, 1 insertions(+), 0 deletions(-)
Merge이루어지면 John브랜치는 아래와 같은 상가 된다.
그림 59. origin/master 브랜치를 Merge 하고 난 후 John의 저장소.
JohnMerge 하고 나서 자신이 작한 코드가 제대로 동작하는지 인한다. 그 후에 유하는 저소에 Push 한다.
$ git push origin master
...
To john@githost:simplegit.git
Ê fbff5bc..72bbc59 master -> master
이제 John의 저소는 아래와 같이 되었다.
130
그림 60. Push 하고 난 후 John의 저장소.
동시에 Jessica토픽 브랜치를 하나 만든다. issue54 브랜치를 만들고 세 에 걸서 커한다. 아직 John의 커
Fetch 하지 않은 상이기 때문에 아래와 같은 상이 된다.
그림 61. Jessica의 토픽 브랜치.
JessicaJohn이 새로 Push했다는 것을 알게 되어 하던 작추고 John의 작내용을 살펴보려고 한다. 하지만
아직 JessicaJohn경사을 가지고 있지 않은 상이다.
# Jessica's Machine
$ git fetch origin
...
From jessica@githost:simplegit
Ê fbff5bc..72bbc59 master -> origin/master
위 명령으로 JohnPush 한 커을 모내려는다. 그러면 Jessica의 저소는 아래와 같은 상가 된다.
131
그림 62. John의 커밋을 Fetch 한 후 Jessica의 저장소.
이제 orgin/master Merge 차례. Jessica토픽 브랜치에서의 작을 마치고 어내용이 Merge 되는지
git log 명령으로 인한다.
$ git log --no-merges issue54..origin/master
commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: John Smith <jsmith@example.com>
Date: Fri May 29 16:01:27 2009 -0700
Ê remove invalid default value
issue54..origin/master 은 히스토리할 때 브랜(origin/master)에 속한 커
브랜(issue54)에 속하지 않은 커하는 문이다. 자세한 내용은 위로 커키기에서 다.
의 명령에 따라 히스토리John이 생성하고 JessicaMerge 하지 않은 커을 하나 았다.
origin/master 브랜치를 Merge 하게 되면 된 커하나가 로Merge 될 것이다.
Merge 할 내용을 인한 Jessica는 자신이 작한 내용과 JohnPush 한 작(origin/master)master
브랜치에 Merge 하고 Push 한다.
issue54 토픽 브랜치에 은 모든 내용을 합치려면, master 브랜치를 Checkout 한다.
$ git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 2 commits, and can be fast-
forwarded.
origin/master, issue54 Upstream 브랜치이기 때문에 둘 중에 무엇을 Merge 하든 상이 없다. 물론
것을 Merge 하느에 따라 히스토리 순서는 달라지지만, 과는 똑같. Jessicaissue54
브랜치를 Merge 한다.
132
$ git merge issue54
Updating fbff5bc..4af4298
Fast forward
ÊREADME | 1 +
Êlib/simplegit.rb | 6 +++++-
Ê2 files changed, 6 insertions(+), 1 deletions(-)
보다시Fast-forward Merge 이기 때문에 명령 실행 결과는 문제가 없다. `origin/master`여있던 John
내용을 다음과 이 실하여 JessicaMerge 할 수 있다.
$ git merge origin/master
Auto-merging lib/simplegit.rb
Merge made by the 'recursive' strategy.
Êlib/simplegit.rb | 2 +-
Ê1 files changed, 1 insertions(+), 1 deletions(-)
와 같Merge되면 그아래와 같은 상가 된다.
그림 63. John의 커밋을 Merge Jessica의 저장소.
origin/master 브랜치가 Jessicamaster 브랜치로 나아갈(reachable) 수 있기 때문에 Push는 성한다(물론
John이 그 사이에 Push 하지 않았다면).
$ git push origin master
...
To jessica@githost:simplegit.git
Ê 72bbc59..8059c15 master -> master
개발자의 커을 성적으로 Merge 하고 나면 과는 아래와 같.
133
그림 64. Jessica가 서버로 Push 하고 난 후의 저장소.
우 간한 상의 예제를 살펴보았다. 토픽 브랜치에서 수정하고 로master 브랜치에 Merge 한다. 한 내용을
프로젝트의 유 저소에 Push 하고자 할 때는 우origin/master 브랜치를 Fetch 하고 Merge 한다. 고 나서
Merge 과를 다시 서버로 Push 한다. 이런 크플로가 일적이며 아래와 같이 나타수 있다.
134
그림 65. 여러 개발자가 Git을 사용하는 워크플로.
비공개 대규모 팀
이제 비개 대모 팀에서의 할을 살펴보자. 이런 상에는 보팀을 여러 개로 나. 서 각각의 작은 팀이 서로
135
어떻게 하나로 Merge 하는지를 살펴.
JohnJessica“featureA을 함하게 됐다. JessicaJosie“featureB도 작하고 있다.
이런 상이라면 회사는 Integration-manager 크플로를 선택하는 게 좋다. 작은 팀이 수Integration-
ManagerMerge 하고 유 저소의 master 브랜치를 데이트한다. 팀마다 브랜치를 하나만들고 Integration-
Manager는 그 브랜치를 Pull 해서 Merge 한다.
팀에 모속한 Jessica의 작순서를 살펴보자. Jessica는 저소를 Clone 하고 featureA 저 한다.
featureA 브랜치를 만들고 수정하고 커한다.
# Jessica's Machine
$ git checkout -b featureA
Switched to a new branch 'featureA'
$ vim lib/simplegit.rb
$ git commit -am 'add limit to log function'
[featureA 3300904] add limit to log function
Ê1 files changed, 1 insertions(+), 1 deletions(-)
이 수정한 부분을 John유해한다. 유하려면 우featureA 브랜치를 서버로 Push 한다. Integration-
Managermaster 브랜치를 데이트할 수 있기 때문에 master 브랜치로 Push를 할 수 없고 다른 브랜치로 John
유한다.
$ git push -u origin featureA
...
To jessica@githost:simplegit.git
Ê* [new branch] featureA -> featureA
Jessica는 자신이 한 일을 featureA 라는 브랜치로 Push 했다는 이일을 John에게 보. John드백을
기다는 동JessicaJosie하는 featureB 을 하기로 한다. 서버의 master 브랜치를 기으로 새로운
브랜치를 하나 만든다.
# Jessica's Machine
$ git fetch origin
$ git checkout -b featureB origin/master
Switched to a new branch 'featureB'
가지 작을 하고 featureB 브랜치에 커한다.
136
$ vim lib/simplegit.rb
$ git commit -am 'made the ls-tree function recursive'
[featureB e5b0fdc] made the ls-tree function recursive
Ê1 files changed, 1 insertions(+), 1 deletions(-)
$ vim lib/simplegit.rb
$ git commit -am 'add ls-files'
[featureB 8512791] add ls-files
Ê1 files changed, 5 insertions(+), 0 deletions(-)
그럼 Jessica의 저소는 그아래와 같.
그림 66. Jessica의 저장소.
을 마치고 Push 하려고 하는데 Jesie가 이“featureB” 을 하고 서버에 featureBee 브랜치로 Push 했다는
일을 보내왔다. JessicaJesie의 작Merge Push 할 수 있다. Merge 하기 위해서 우git
fetch Fetch 한다.
$ git fetch origin
...
From jessica@githost:simplegit
Ê* [new branch] featureBee -> origin/featureBee
JessicaCheckout featureB 브랜치에서 작중일 때, Fetch 해 온 브랜치를 git merge 명령으로 Merge
한다.
137
$ git merge origin/featureBee
Auto-merging lib/simplegit.rb
Merge made by the 'recursive' strategy.
Êlib/simplegit.rb | 4 ++++
Ê1 files changed, 4 insertions(+), 0 deletions(-)
이 시에서 JissicaMerge “featureB을 서버로 Push 할 때 서버의 featureB 브랜치로 Push하지 않고자
한다. Josie가 생성한 `featureBee`로 작내용을 Push 하러면 아래와 같이 실한다.
$ git push -u origin featureB:featureBee
...
To jessica@githost:simplegit.git
Ê fba9af8..cd685d1 featureB -> featureBee
이것은 refspec 것을 사용하는 것인데 Refspec 에서 자세하게 명한다. 명령에서 사용한 -u 옵션--set
-upstream 옵션표현인데 브랜치를 추적하도록 정해서 이후 Push Pull 할 때 좀 더 편하게 사용할 수 있다.
John가지 작을 하고 나서 featureA Push 했고 인해 달라는 내용의 이일을 보내왔다. Jessica
John의 작내용을 인하기 위해 다시 한 git fetch Push된 작Fetch 한다.
$ git fetch origin
...
From jessica@githost:simplegit
Ê 3300904..aad881d featureA -> origin/featureA
Jessica의 로featureA 브랜Fetch 해 온 John의 작내용이 featureA 브랜치 상에서 어것이
데이트됐는지 git log 명령으로 인한다.
$ git log featureA..origin/featureA
commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6
Author: John Smith <jsmith@example.com>
Date: Fri May 29 19:57:33 2009 -0700
Ê changed log output to 30 from 25
인을 마치면 로featureA 브랜치로 John의 작내용을 다음과 Merge 한다.
138
$ git checkout featureA
Switched to branch 'featureA'
$ git merge origin/featureA
Updating 3300904..aad881d
Fast forward
Êlib/simplegit.rb | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
Jessica는 일부 수정하고, featureA 브랜치에 커하고, 수정한 내용을 다시 서버로 Push 한다.
$ git commit -am 'small tweak'
[featureA 774b3ed] small tweak
Ê1 files changed, 1 insertions(+), 1 deletions(-)
$ git push
...
To jessica@githost:simplegit.git
Ê 3300904..774b3ed featureA -> featureA
와 같은 작을 마치고 나면 Jessica의 저소는 아래와 같은 모습이 된다.
그림 67. 마지Push 하고 난 후의 Jessica의 저장소.
그럼 featureA featureBee 브랜치가 프로젝트의 브랜치로 Merge 비가 되었다고 Integration-
Manager에게 알려. Integration-Manager두 브랜치를 모Merge 하고 난 후에 브랜치를 Fetch 하면
아래와 같은 모이 된다.
139
그림 68. 두 브랜치가 메인 브랜치에 Merge 된 후의 저장소.
수많은 팀의 작을 동시에 진행하고 나중에 Merge 하는 기을 사용하려고 다른 버전 관리 시스에서 Git으로 바
조직들이 많지고 있다. 팀은 자신의 브랜치로 작하지만, 브랜치에 영치지 않는다는 Git장점이다.
아래는 이런 크플로를 나타내고 있다.
140
그림 69. Managed 팀의 워크플로.
공개 프로젝트 Fork
개 팀을 운영하는 것과 개 팀을 운영하는 것은 간 다. 개 팀을 운영할 때는 모든 개발자가 프로젝트의
소에 접적으로 쓰기 한을 가지지는 않는다. 서 프로젝트의 관리자는 가지 일을 더 해한다. Fork
지원하는 Git 호스팅에서 Fork해 프로젝트에 기여하는 을 예제를 해 살펴. Git 호스팅 사이트(GitHub,
141
BitBucket, repo.or.cz ) 대부분은 Fork 을 지원하며 프로젝트 관리자는 보Fork 하는 것으로 프로젝트를
운영한다. 다른 방식으로 이일과 Patch를 사용하는 방식도 있는데 이어 살펴.
처음 할 일은 인 저소를 Clone 하는 것이다. 고 나서 토픽 브랜치를 만들고 일정 부분 기여한다. 그 순서는
아래와 같.
$ git clone <url>
$ cd project
$ git checkout -b featureA
Ê ... work ...
$ git commit
Ê ... work ...
$ git commit
rebase -i 명령을 사용하면 여러 커을 하나의 커으로 합치거나 프로젝트의 관리자가
수정사을 쉽게 이해하도록 커을 정할 수 있다. 히스토리 단장하기 에서 대화식으로 Rebase
하는 방법을 살펴.
프로젝트의 웹사이트로 가서 “Fork누르면 원프로젝트 저소에서 나온, 쓰기 한이 있는
소가 하나 만들어. 그러면 로에서 수정한 커을 원소에 Push 할 수 있다. 그 저소를 로소의
모트 저소로 등록한다. 예를 들어 `myfork`로 등록한다.
$ git remote add myfork <url>
자 이제 등록한 모트 저소에 Push 한다. 하던 것을 로소의 master 브랜치에 Merge 한 후 Push 하는
것보다 모트 브랜치에 바로 Push를 하는 방식훨씬 하다. 게 하는 이유는 관리자가 토픽 브랜치를
프로젝트에 포함시키고 지 않을 때 토픽 브랜치를 Merge 하기 이전 상master 브랜치를 되돌릴 필요가 없기
때문이다. (cherry-pick 명령은 RebaseCherry-Pick 크플로 에서 자세히 다). 관리자가 토픽 브랜치를
Merge 하든 Rebase 하든 Cherry-Pick 하든지 간에 다시 관리자의 저소를 Pull 할 때는 토픽 브랜치의 내용이
들어 있을 것이다.
경우라도 다음과 이 작내용을 Push 할 수 있다.
$ git push -u myfork featureA
Fork 한 저소에 Push 하고 나면 프로젝트 관리자에게 이 내용을 알려한다. 이것을 Pull Request 라고 한다. Git
호스팅 사이트에서 관리자에게 보시지를 생성하거나 git request-pull 명령으로 이일을 수동으로 만들 수
있다. GitHub“Pull Request” 은 자동으로 시지를 만들어 주는데 관련 내용은 GitHub 에서 살펴볼 수 있다.
git request-pull 명령은 아규먼트를 개 입력는다. 번째 아규먼트는 작토픽 브랜치의 Base
브랜치이다. 두 번째토픽 브랜치가 위치한 저URL인데 위에서 등록한 모트 저소 이름을 적을 수 있다.
명령은 토픽 브랜치 수정사을 요한 내용을 과로 보여. 예를 들어 JessicaJohn에게 Pull 을 보내는
142
을 살펴보자. Jessica토픽 브랜치에 두 번 을 하고 Fork 한 저소에 Push 했다. 아래와 같
한다.
$ git request-pull origin/master myfork
The following changes since commit
1edee6b1d61823a2de3b09c160d7080b8d1b3a40:
Jessica Smith (1):
Ê added a new function
are available in the git repository at:
Ê git://githost/simplegit.git featureA
Jessica Smith (2):
Ê add limit to log function
Ê change log output to 30 from 25
Êlib/simplegit.rb | 10 +++++++++-
Ê1 files changed, 9 insertions(+), 1 deletions(-)
관리자에게 이 내용을 보. 이 내용에는 토픽 브랜치가 어느 시나온 것인지, 이 있는지, Pull
하려면 어소에 접하는지에 대한 내용이 들어 있다.
프로젝트 관리자가 니라고 해도 보origin/master 를 추적하는 master 브랜치는 가지고 있다. 토픽
브랜치를 만들고 일을 하면 관리자가 수정 내용을 거부할 때 쉽게 버수 있다. 토픽 브랜치를 만들어서 주제
독립적으로 일을 하는 동에도 주 저소의 master 브랜치는 계속 수정된다. 하지만 주 저소의 브랜치의 최근
이후로 Rebase 하면 깨끗하게 Merge 할 수 있다. 고 다른 주제의 일을 하려고 할 때는 Push 토픽 브랜치에서
시작하지 고 주 저소의 master 브랜치로부터 만들어한다.
$ git checkout -b featureB origin/master
Ê ... work ...
$ git commit
$ git push myfork featureB
$ git request-pull origin/master myfork
Ê ... email generated request pull to maintainer ...
$ git fetch origin
토픽은 일의 실실이라고 할 수 있다. 토픽은 서로 해하지 않고 독립적으로 수정하고 Rebase 할 수 있다.
143
그림 70. featureB 수정작업이 후 저장소의 모습.
프로젝트 관리자가 사람들의 수정 사Merge 하고 나서 Jessica브랜치를 Merge 하려고 할 때 수도 있다.
그러면 Jessica가 자신의 브랜치를 origin/master Rebase 해서 을 해하고 다시 Pull Request을 보.
$ git checkout featureA
$ git rebase origin/master
$ git push -f myfork featureA
위 명령들을 실하고 나면 히스토리아래와 같아진.
그림 71. FeatureA에 대한 Rebase가 적용된 후의 모습.
브랜치를 Rebase 해 버렸기 때문에 Push 할 때 -f 옵션을 주고 제로 기존 서버에 있던 featureA 브랜치의 내용을
어 써한다. 니면 새로운 브랜치를(예를 들어 featureAv2) 서버에 Push 해도 된다.
또 다른 시나오를 하나 더 살펴보자. 프로젝트 관리자는 featureB 브랜치의 내용은 좋지만, 상세 구현은 다게 하고
. 관리자는 featureB 당자에게 상세 구현을 다게 해달라고 요한다. featureB 당자는 하는
featureB 브랜치를 프로젝트의 master 브랜치 기으로 . origin/master 브랜치에서
featureBv2 브랜치를 새로 하나 만들고, featureB 의 커들을 모Squash 해서 Merge 하고, 이 나면
하고, 상세 구현을 수정하고, 브랜치를 Push 한다.
144
$ git checkout -b featureBv2 origin/master
$ git merge --squash featureB
Ê ... change implementation ...
$ git commit
$ git push myfork featureBv2
--squash 옵션브랜치에 Merge 할 때 해당 브랜치의 커을 모하나로 합Merge 한다. 이 때 Merge
은 만들지 않는다. 다른 브랜치에서 수정한 사을 전부 가오는 것은 똑같. 하지만 새로 만들어지는 커은 부모가
하나이고 커을 기록하기 전에 좀 더 수정할 기회도 있다. 다른 브랜치에서 수정한 사을 전부 가오면서 그전에
추가적으로 수정할 게 있으면 수정하고 Merge 할 수 있다. 게다가 새로 만들어지는 커은 부모가 하나다. --no
-commit 옵션을 추가하면 커을 합놓고 자동으로 커하지 않는다.
수정을 마치면 관리자에게 featureBv2 브랜치를 인해 보라고 시지를 보.
그림 72. featureBv2 브랜치를 커밋한 이후 저장소 모습.
대규모 공개 프로젝트와 이메일을 통한 관리
모 프로젝트는 보수정사이나 Patch를 수용하는 자신만의 규칙을 마해놓고 있다. 프로젝트마다 규칙은 서로
다를 수 있으로 각 프로젝트의 규칙미리 요가 있다. 된 대모 프로젝트는 대부분 스트를
해서 Patch받아들이는데 예제를 해 살펴.
토픽 브랜치를 만들어 수정하는 작서 살펴거의 비하지만, Patch를 제출하는 방식이 다. 프로젝트를
Fork 하여 Push 하는 것이 니라 커내용을 일로 만들어 개발자 스트에 제출한다.
$ git checkout -b topicA
Ê ... work ...
$ git commit
Ê ... work ...
$ git commit
145
두 번 하고 스트에 보내 보자. git format-patch 명령으로 스트에 보mbox 형식
일을 생성한다. 각 커은 하나시지로 생성되는데 커밋 메시지의 번째 라인이 제목이 되고 Merge 시지
내용과 Patch 시지의 문이 된다. 방식은 수신한 이일에 들어 있는 Patch를 바로 적용할 수 있어서
좋다. 일 속에는 커의 모든 내용이 포함된다. 일에 포함된 Patch를 적용하는 것은 다음 절에서 살펴.
$ git format-patch -M origin/master
0001-add-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
format-patch 명령을 실하면 생성한 일 이름을 보여. -M 옵션은 이름이 경된 일이 있는지 살펴보라는
옵션이다. 일의 내용은 아래와 같.
$ cat 0001-add-limit-to-log-function.patch
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function
Limit log functionality to the first 20
---
Êlib/simplegit.rb | 2 +-
Ê1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 76f47bc..f9815f1 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -14,7 +14,7 @@ class SimpleGit
Ê end
Ê def log(treeish = 'master')
- command("git log #{treeish}")
+ command("git log -n 20 #{treeish}")
Ê end
Ê def ls_tree(treeish = 'master')
--
2.1.0
스트에 이일을 보내기 전에 각 Patch 일을 으로 고수 있다. --- 라인과 Patch가 시작되는 라인(diff
--git 로 시작하는 라인) 사이에 내용을 추가하면 다른 개발자는 을 수 있지만, 나중에 Patch에 적용되지는 않는다.
특정 일 프로그을 사용하거나 이일을 보내는 명령어로 스트에 보수 있다. 기로 위의 내용이
그대로 들어가지 않는 일 프로그도 있다. 사용자 편의를 위해 백이나 라인 바문자 등을 어 주는
프로그은 원그대로 들어가지 않는다. Git에는 Patch 일을 그대로 보수 있는 도가 있다. IMAP
146
프로토콜로 보. 저자가 사용하는 방법으로 Gmail을 사용하여 Patch 일을 전송하는 방법을 살펴보자. 추가로 Git
프로젝트의 Documentation/SubmittingPatches 문서의 마지부분을 살펴보면 다일 프로그으로
일을 보내는 방법명한다.
일을 보내려면 ~/.gitconfig 일에서 이일 부분 정한다. git config 명령으로 추가할 수도 있고
일을 열어서 추가할 수도 있다. , 아래와 같정을 한다.
[imap]
Ê folder = "[Gmail]/Drafts"
Ê host = imaps://imap.gmail.com
Ê user = user@gmail.com
Ê pass = YX]8g76G_2^sFbd
Ê port = 993
Ê sslverify = false
IMAP 서버가 SSL을 사용하지 않으면 마지막 두 라인은 요 없고 host에서 imaps:// 대신 imap:// 로 한다.
정하면 git imap-send 명령으로 Patch 일을 IMAP 서버의 Draft 더에 이일로 보수 있다.
$ cat *.patch |git imap-send
Resolving imap.gmail.com... ok
Connecting to [74.125.142.109]:993... ok
Logging in...
sending 2 messages
100% (2/2) done
이후 GmailDraft 더로 가서 To 부분을 스트의 주소로 경하고 CC 부분에 해당 일을 참고해하는
관리자나 개발자의 일 주소를 적고 실제로 전송한다.
SMTP 서버를 이용해서 Patch를 보수도 있다. SMTP 서버를 정해한다. git config 명령으로 하나
정할 수도 있지만 아래와 같~/.gitconfig 일의 sendemail 섹션으로 접 고도 된다.
[sendemail]
Ê smtpencryption = tls
Ê smtpserver = smtp.gmail.com
Ê smtpuser = user@gmail.com
Ê smtpserverport = 587
정하면 git send-email 명령으로 치를 보수 있다.
147
$ git send-email *.patch
0001-added-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
Who should the emails appear to be from? [Jessica Smith
<jessica@example.com>]
Emails will be sent from: Jessica Smith <jessica@example.com>
Who should the emails be sent to? jessica@example.com
Message-ID to be used as In-Reply-To for the first email? y
명령을 실하면 아래와 같이 서버로 Patch를 보내는 내용이 면에 나타난다.
(mbox) Adding cc: Jessica Smith <jessica@example.com> from
Ê \line 'From: Jessica Smith <jessica@example.com>'
OK. Log says:
Sendmail: /usr/sbin/sendmail -i jessica@example.com
From: Jessica Smith <jessica@example.com>
To: jessica@example.com
Subject: [PATCH 1/2] added limit to log function
Date: Sat, 30 May 2009 13:29:15 -0700
Message-Id: <1243715356-61726-1-git-send-email-jessica@example.com>
X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty
In-Reply-To: <y>
References: <y>
Result: OK
요약
절에서는 다크플로에 따라 Git을 어떻게 사용하는지 살펴보고 그에 요한 도들을 명했다. 다음 절에서는
동전의 면인 프로젝트를 운영하는 방법에 대하여 살펴. 절한 DictatorIntegration-Manager가 되어 보는
것이다.
프로젝트 관리하기
효율적으로 기여하는 방법뿐만 니라 효율적으로 운영하는 방법도 알아야 한다. 가는 순히 프로젝트에 기여하는
것이 니라 프로젝트를 접 운영해할 수도 있다. 프로젝트를 운영하는 것은 크게 가지로 이루어. 하나는
format-patch 명령으로 생성한 Patch를 이일로 받아서 프로젝트에 Patch를 적용하는 것이다. 다른 하나는
프로젝트의 다른 모트 저소로부터 경 내용을 Merge 하는 것이다. 소를 깔끔하고 정된 상로 운영하고
Patch를 적용하거나 수정사인하기 운 상로 유지하려면 좋은 운영 방식을 터한다. 좋은 운영 방식
다른 사람들이 이해하기 쉽고 프로젝트가 오랫동운영도 흐트러이 없어한다.
148
토픽 브랜치에서 일하기
브랜치에 합하기 전에 시로 토픽 브랜치를 하나 만들고 거기에 합해 보고 나서 다시 브랜치에 합하는
것이 좋다. 게 하면 Patch를 적용할 때 이수정해 보기도 하고 좀 더 고민해 하면 Patch를 적용해
나중으로 미룰 수도 있다. Patch인지 브랜치 이름에 간히 적어주면 다른 작을 하다가 나중에 이 브랜치로
돌아왔을 때 기해내기 훨씬 하다. 프로젝트 관리자라면 이런 토픽 브랜치의 이름을 지어한다. 예를 들어 sc
라는 사람이 작Patch라면 sc/ruby_client 처럼 네임여서 브랜치를 만들 수 있다. master
브랜치에서 새 토픽 브랜치를 아래와 같이 만든다.
$ git branch sc/ruby_client master
checkout -b 명령으로 브랜치를 만들고 Checkout까지 한 에 할 수 있다.
$ git checkout -b sc/ruby_client master
토픽 브랜치를 만들고 Patch를 적용해보고 적용한 내용을 다시 Long-Running 브랜치로 Merge 한다.
이메일로 받은 Patch를 적용하기
일로 Patch를 프로젝트에 적용하기 전에 우선 토픽 브랜치에 Patch를 적용한다. Patch를 적용하는 방법git
apply 명령을 사용하는 것과 git am 명령을 사용하는 것 가지가 있다.
apply 명령을 사용하는 방법
git diff Unixdiff 명령(다음 절에서 다루지만 추천하지 않는 방법)으로 만든 Patch 일을 적용할 때는 git
apply 명령을 사용한다. Patch 일이 /tmp/patch-ruby-client.patch 라고 하면 아래와 같은 명령으로
Patch를 적용할 수 있다.
$ git apply /tmp/patch-ruby-client.patch
위 명령을 실하면 Patch 일 내용에 따라 재 디렉토리일들을 경한다. 위 명령은 patch -p1 명령과 거의
. 하지만, 이 명령이 patch 명령보다 훨씬 꼼꼼하게 비한다. git diff 로 생성한 Patch 일에 일을
추가하거나, 일을 제하고, 일의 이름을 경하는 내용이 들어 있으면 그대로 적용된다. 이런 것은 patch 명령으로
할 수 없다. git apply 적용, 니면 모을 사용하기 때문에 Patch를 적용하는 데
하면 Patch를 적용하기 이전 상로 전부 되려 놓는다. patch 명령은 여러 일에 적용하다가 중간에 실하면
거기서 그대로 중하기 때문에 깔끔하지 못하다. git apply patch 명령보다 훨씬 보수적이다. 이 명령은 자동으로
해 주지 않기 때문에 경된 일을 Staging Area에 추가하고 커한다.
실제로 Patch를 적용하기 전에 Patch적용되는지 한 해보려면 git apply --check 명령을 사용한다.
149
$ git apply --check 0001-seeing-if-this-helps-the-gem.patch
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
면에 무 내용도 지 않으면 Patch깔끔하게 적용됐다는 것이다. 이 명령은 Patch를 적용해 보고 에러가 발생하면
0닌 값환하기 때문에 스크트에서도 사용할 수 있다.
am 명령을 사용하는 방법
프로젝트 기여자가 Gitformat-patch 명령을 사용하면 관리자의 작훨씬 워진. format-patch 명령으로
만든 Patch 일은 기여자의 정보정보가 포함되어 있기 때문이다. 서 기여자가 diff보다 format-patch
사용하도록 한다. git apply 는 기존 Patch 일에만 사용한다.
format-patch 명령으로 생성한 Patch 일은 git am 명령으로 적용한다(am "apply a series of patches from
a mailbox"자다). git am mbox 일을 어 그 에 이시지가 한 개가 있든 여러 개가 있든 처할 수
있다. mbox 일은 간스트 일이고 그 내용은 아래와 같.
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function
Limit log functionality to the first 20
이 내용은 format-patch 명령으로 생성한 일의 부분이다. 일은 mbox 형식이다. 일이 git
send-email 로 만든 일이라면 mbox 형식으로 저하고 이 mbox 일을 git am 명령으로 적용한다. 사용하는
라이트가 여러 이일을 mbox 일 하나로 저할 수 있다면 일 여러 개를 한 Patch 할 수 있다.
일로 은 것이 니라 git format-patch 명령으로 만든 이시스템 같은데 라온 일이라면
내려고서 git am 명령으로 Patch 한다.
$ git am 0001-limit-log-function.patch
Applying: add limit to log function
Patch가 성하면 자동으로 새로운 커이 하나 만들어. 일의 From Date 에서 저자 정보가, 일의 제목과
시지에서 커밋 메시지가 추출사용된다. 예를 들어 위의 mbox 예제 일을 적용해서 생성되는 커아래와 같.
150
$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author: Jessica Smith <jessica@example.com>
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit: Scott Chacon <schacon@gmail.com>
CommitDate: Thu Apr 9 09:19:06 2009 -0700
Ê add limit to log function
Ê Limit log functionality to the first 20
Commit 부분의 커정보는 Patch 했는지 알려 . Author 정보는 실제로 Patch 일을
만들었는지 알려 .
Patch에 실할 수도 있다. Patch가 생성된 시보다 해당 브랜치가 데이트 됐을 때나 아직 적용되지 않은
다른 Patch요한 경우에 일어난다. 이러면 git am 명령은 Patch를 중하고 사용자에게 어떻게 처할지 어온다.
$ git am 0001-seeing-if-this-helps-the-gem.patch
Applying: seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Patch failed at 0001.
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".
적으로 Patch 하지 못하면 gitMerge Rebase 의 경우처럼 문제를 일으일에 돌 표시를 해 놓는다.
Merge Rebase 할 때 을 해하는 것처럼 Patch도 해할 수 있다. 일을 열어서 부분을
수정하고 나서 Staging Area에 추가하고 git am --resolved 명령을 입력한다.
$ (fix the file)
$ git add ticgit.gemspec
$ git am --resolved
Applying: seeing if this helps the gem
을 때 Git에게 좀 더 머리를 써서 Patch를 적용하도록 하려면 -3 옵션을 사용한다. 옵션Git에게 3-way
Patch를 적용해 보라고 하는 것이다. Patch가 어느 시에서 나온 것인지 알 수 없기 때문에 이 옵션은 기적으로
비활성화돼 있다. 하지만 은 프로젝트의 커이라면 기옵션보다 훨씬 똑똑하게 을 해한다.
151
$ git am -3 0001-seeing-if-this-helps-the-gem.patch
Applying: seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.
위의 경우에서 -3 옵션이 없었으면 을 것이다. -3 옵션이 있어서 없이 깨끗하게 Patch가 적용됐다.
하나의 mbox 일에 들어 있는 여러 Patch를 적용할 때 am 명령의 대화형 방식을 사용할 수 있다. 방식을 사용하면
Patch를 적용할 때마다 는다.
$ git am -3 -i mbox
Commit Body is:
--------------------------
seeing if this helps the gem
--------------------------
Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all
옵션Patch를 여러 개 적용할 때 유용하다. 적용하려는 Patch의 내용을 미리 지 않도 되고 적용하기
전에 이적용된 Patch인지 알 수 있다.
모든 Patch토픽 브랜치에 적용하고 커까지 마치면 Long-Running 브랜치에 어떻게 합할지를 정해한다.
리모트 브랜치로부터 통합하기
프로젝트 기여자가 자신의 저소를 만들고 커몇 번 하고 저소의 URL경 내용을 일로 보내왔다면 URL
모트 저소로 등록하고 Merge 할 수 있다.
예를 들어 Jessicaruby-client 브랜치에 엄청난 기을 만들어 다고 이일을 보내왔다. 모트 브랜치를
등록하고 Checkout 해서 스트한다.
$ git remote add jessica git://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client
나중에 Jessiaca가 이일로 또 다른 엄청난 기을 개발한 브랜치를 보내오면 이소를 등록했기 때문에 바로
Fetch 하고 Checkout 할 수 있다.
다른 개발자들과 함지속적으로 개발할 때는 이 방식이 가사용하기 좋다. 물론 기여하는 사람이 간Patch
이따금만 만들어 내면 이일로 Patch 일을 는 것이 . 기여자가 저소 서버를 만들어 커하고 관리자가
모트 저소로 등록해서 Patch를 합치는 작보다 시간과 노력이 든다. 물론 Patch 개를 보내는 사람들까지도
152
두 리모트 저소로 등록해서 사용해도 된다. 스크트나 호스팅 서비스를 사용하면 좀 더 쉽게 관리할 수 있다.
떤 방식이 좋을지는 우가 어떻게 개발하고 어떻게 기여할지에 달렸다.
모트 저소로 등록하면 커의 히스토리도 알 수 있다. Merge 할 때 어디서부터 커는지 알 수 있기 때문에
-3 옵션을 주지 않도 자동으로 3-way Merge가 적용된다.
모트 저소로 등록하지 않고도 Merge 할 수 있다. 계속 함일할 개발자가 때 사용하면 좋다. 아래모트
소로 등록하지 않고 URL접 사용하여 Merge를 하는 예이다.
$ git pull https://github.com/onetimeguy/project
From https://github.com/onetimeguy/project
Ê* branch HEAD -> FETCH_HEAD
Merge made by the 'recursive' strategy.
무슨 내용인지 확인하기
기여이 포함된 토픽 브랜치가 있으니 이제 그 기여Merge 할지 정해한다. 절에서는 브랜치에
Merge 할 때 요한 명령어를 살펴. 주로 토픽 브랜치를 하는데 요한 명령이다.
저 지금 작하는 브랜치에서 master 브랜치에 속하지 않는 커만 살펴보는 것이 좋다. --not 옵션으로
히스토리에서 master 브랜치에 속한 커은 제외하고 살펴. 서 살펴master..contrib 형식을 사용하여
인할 수도 있다. contrib 브랜치에 PatchMerge 했으면 아래와 같은 명령어로 그 과를 살펴볼 수 있다.
$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Oct 24 09:53:59 2008 -0700
Ê seeing if this helps the gem
commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date: Mon Oct 22 19:38:36 2008 -0700
Ê updated the gemspec to hopefully work better
git log 명령에 -p 옵션을 주면 각 커에서 실제로 무내용이 경됐는지 살펴볼 수 있다. 옵션은 각 commit
diff의 내용을 출력해 .
토픽 브랜치를 다른 브랜치에 Merge 하기 전에 어부분이 경될지 미리 살펴볼 수 있다. 이때는 다른 명령을
사용해한다. 물론 아래와 같은 명령을 사용할 수도 있다.
$ git diff master
153
이 명령은 diff 내용을 보여주하지만 못된 것을 보여수도 있다. 토픽 브랜치에서 작하는 동master 브랜치에
새로운 커이 추가될 수도 있다. 기 때문에 기대하는 diff 과가 수 있다. 위 명령은 토픽 브랜치의 마지
master 브랜치의 마지을 비한다. master 브랜치에 한 을 추가되면 토픽 브랜치에서 한 제한
것으로 보여 .
master 브랜치가 가키는 커토픽 브랜치의 상이라면 무 문제 없다. 하지만, 지 않은 경우라면 이 diff
토픽 브랜치에만 있는 내용은 추가하는 것이고 master 브랜치에만 있는 내용은 제하는 것으로 간주한다.
보고 은 것은 토픽 브랜치에 추가한 것이고 에는 이것을 master 브랜치에 추가하려는 것이다. 그러니까
master 브랜와 토픽 브랜치의 공통 조상인 커찾아토픽 브랜치가 재 가키는 커과 비한다.
아래와 같은 명령으로 공통 조상인 커고 이 상 커에서 경된 내용을 살펴.
$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db
은 내용을 명령 한 로 실하면 다음과 .
$ git diff $(git merge-base contrib master)
방법으로 원하는 과를 을 수 있지만, 사용편하다. GitTriple-Dot 문으로 간하게 위와 같이 비하는
방법을 지원한다. diff 명령을 사용할 때 두 브랜치 사이에 `…`를 쓰면, 두 브랜치의 공통 조상과 브랜치의 마지
을 비한다.
$ git diff master...contrib
이 명령은 master 브랜와 현토픽 브랜치에서 달라것들만 보여주기 때문에 기우 유용하게 사용할 수
있다.
기여물 통합하기
기여토픽 브랜치에 다 적용하고 Long-Running 브랜치나 master 브랜치로 합할 비가 되었다면 이제 어떻게
할까. 프로젝트를 운영하는 데 쓰는 작업 방식은 어것이 있을까. 으로 그 예제 가지를 살펴.
Merge 하는 워크플로
바로 master 브랜치에 Merge 하는 것이 가하다. 크플로에서는 master 브랜치가 전한 코드라고
가정한다. 토픽 브랜치에서 작을 하고 작나면 토픽 브랜치를 검증하고 master 브랜치로 Merge 한 후 토픽
브랜치를 제하는 과정을 반복한다.
154
여러 토픽 브랜치 히스토리. 처럼 ruby_client 브랜php_client 브랜치가 있을 때 ,ruby_client 브랜치를
master 브랜치로 Merge 한 후 php_client 브랜치를 Merge 하면 Merge 한 후의 저. 같아진.
그림 73. 여러 토픽 브랜치 히스토리.
그림 74. Merge 한 후의 저장소.
크플로에서 가한 시나오다. 프로젝트의 모가 커지거나 코드를 더 정적으로 관리할 때는 이게 쉽게
Merge 되지 않을 것이다.
개발자가 많고 모가 프로젝트에서는 소한 두 단계로 Merge 하는 것이 좋다. 살펴볼 예에서는 Long-Running
브랜치를 개를 유지한다. master 브랜치는 정적인 버전을 릴리즈하기 위해서 사용한다. develop 브랜치는
새로 수정된 코드를 합할 때 사용한다. 두 브랜치를 모두 공개 저소에 Push 한다. develop 브랜치에 토픽
브랜(토픽 브랜치를 Merge 하기 전.)토픽 브랜치를 Merge 한 후. Merge 한다. 그 후에 릴리즈해도 될만한
이 되면 master 브랜치를 develop 브랜치까지 Fast-forward(토픽 브랜치를 릴리즈한 후.).
155
그림 75. 토픽 브랜치를 Merge 하기 전.
그림 76. 토픽 브랜치를 Merge 한 후.
그림 77. 토픽 브랜치를 한 후.
156
크플로를 사용하면 프로젝트 저소를 Clone 하고 나서 개발자가 정 버전이 요하면 master 브랜치를 드하고
정적이지 않더라도 좀 더 신 버전이 요하면 develop 브랜치를 Checkout 하여 드한다. 이 개념을 좀 더 확장해서
사용할 수 있다. 토픽 브랜치를 검증하기 위한 integrate 브랜치를 만들어 Merge 하고 토픽 브랜치가 검증되면
develop 브랜치에 Merge 한다. develop 브랜치에서 분히 정하다는 것이 명되면 그때 master 브랜치에
Fast-forward Merge 한다.
대규모 Merge 워크플로
Git을 개발하는 프로젝트는 Long-Running브랜치를 4개 운영한다. 브랜치 이름은 master, next, pu (Proposed
Updates), maint 이다. maint 는 마지으로 릴리즈한 버전을 지원하는 브랜치다. 기여자가 새로운 기을 제하면
관리자는 토픽 브랜치를 동시에 여러 개 관리하는 것은 복잡하다. 처럼 자신의 저소에 토픽 브랜치를 만들어 관리한다.
토픽에 부은 없는지, 정적인지 계속 스트한다. 되면 next Merge 하고 저소에 Push 한다.
그러면 모잘 통합됐는지 인할 수 있다.
그림 78. 토픽 브랜치를 동시에 여러 개 관리하는 것은 복잡하다.
토픽 브랜치가 좀 더 개선돼야 하면 next 니라 pu Merge 한다. 분히 검증을 했을 때에만 master 브랜치로
Merge 한다. master 브랜치에 Merge하고 나면 next 브랜pu 브랜치는 master 브랜치를 기으로 다시 만든다.
next 브랜치는 정Rebase 하고 pu 는 자주 Rebase 하지만 master Fast-forward 한다.
157
그림 79. 토픽 브랜치를 Long-Running 브랜치로 Merge 하기.
토픽 브랜치가 master 브랜치로 Merge 되면 저소에서 제한다. 고 이전 릴리즈 버전에 Patch요하면
maint 브랜치를 이용해 대한다. Git을 개발하는 프로젝트를 Clone 하면 브랜치가 4개 있고 각 브랜치를 이용하여
진행인해볼 수 있다. 서 새로운 기을 추가하려면 적당한 브랜치를 보고 고른다. 크플로는 잘 구조화돼
있어서 코드가 새로 추가스트하기 쉽다. Git 프로젝트의 크플로는 이다. 완벽하게 이해하려면 Git
관리자 가이드한다.
RebaseCherry-Pick 워크플로
히스토리를 한 관리하려고 Merge 보다 Rebase Cherry-Pick을 더 호하는 관리자들도 있다. 토픽 브랜치에서
을 마master 브랜치에 Merge 할 때 master 브랜치를 기으로 Rebase 한다. 그러면 커이 다시 만들어
. master 대신 develop 등의 브랜치에도 가하다. 문제가 없으면 master 브랜치를 Fast-forward.
게 히스토리를 한 로 유지할 수 있다.
브랜치에서 다른 브랜치로 작한 내용을 기는 또 다른 방식으로 Cherry-pick것도 있다. GitCherry-pick
하나만 Rebase 하는 것이다. 하나로 Patch 내용을 만들어 브랜치에 적용을 하는 것이다. 토픽 브랜치에
있는 커중에서 하나만 고거나 토픽 브랜치에 커이 하나에 없을 때 Rebase 보다 유용하다. 아래와 같은 예를
들어보자.
158
그림 80. Cherry-pick을 실행하기 전의 저장소.
e43a6 하나만 master 브랜치에 적용하려면 아래와 같은 명령을 실한다.
$ git cherry-pick e43a6
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index
fails."
Ê3 files changed, 17 insertions(+), 3 deletions(-)
위 명령을 실하면 e43a6 에서 경된 내용을 브랜치에 똑같이 적용을 한다. 하지만, 경을 적용한 시
르므로 새 커SHA-1 해시은 달라. 명령을 실하고 나면 아래와 같이 된다.
159
그림 81. Cherry-pick 식으로 커밋 하나를 적용한 후의 저장소.
Rebase Cherry-pick 방식으로 토픽 브랜치를 합치고 나면 요없는 토픽 브랜치나 커제한다.
Rerere
수시로 Merge Rebase를 한다거나 오랫동유지되는 토픽브랜치를 쓰는 사람에게 유용한 “rerere” 이 있다.
Rerere“reuse recorded resolution”(결방법 재사용)으로 수작으로 하던 것을 쉽게 해.
rerere 이 활성화 돼 있으면 Merge가 성할 때 마다 그 이전과 이후 상를 저. 나중에 이 발생하면
한 상에서 Merge가 성한 적이 있었는지 찾아보고 해이 가하다면 자동으로 해한다.
Rerere 의 동작은 부분으로 나어 볼 수 있다. Rerere 정하는 부분과 Rerere 을 명령으로 사용하는
부분이다. 정은 rerere.enabled 정하면 되는데 로벌 정에 저고 사용하면 편하다.
$ git config --global rerere.enabled true
이제부터 Merge가 성할 때 마다 전후 상을 기록해고 나중에 이 나면 사용할 수 있게 됐다.
요하다면 git rerere 명령을 사용하여 저시를 바으로 대화형 인터이스를 을 다수도 있다.
git rerere 명령을 접 실하면 Merge 과정에서 발생한 을 해하는데 참고할 만한 이전 Merge 기록을
찾아준(rerere.enabled 옵션있다면 자동). Rerere 을 사용할 때 기록할 내용을 세세하게 정하거나,
기록된 내용 중에 특정 기록을 지운다거나 하는 보명령도 제한다. 자세한 내용은 Rerere 에서 다루기로 한다.
릴리즈 버전에 태그 달기
적당한 때가 되면 릴리즈해한다. 제든지 그 시으로 되돌릴 수 있게 그를 다는 것이 좋다. Git의 기에서
160
살펴대로 그를 달면 된다. 서명된 그를 달면 아래와 같이 출력된다.
$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09
그에 서명하면 서명에 사용한 PGP 개키도 배포해한다. Git 개발 프로젝트는 관리자의 PGP 개키를 Blob
형식으로 Git 소에 함배포한다. Blob 일을 사용하여 그에 서명했다. gpg --list-keys 명령으로 어
PGP 개키를 포함할지 인한다.
$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub 1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid Scott Chacon <schacon@gmail.com>
sub 2048g/45D02282 2009-02-09 [expires: 2010-02-09]
git hash-object 라는 명령으로 개키를 바로 Git 소에 을 수 있다. 이 명령은 Git Blob 형식으로
개키를 저해주고 그 BlobSHA-1 을 알려.
$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92
hash-object 명령으로 SHA-1 해시으로 PGP 개키를 가키는 그를 만든다.
$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92
git push --tags 명령으로 서 만든 maintainer-pgp-pub 그를 유한다. 다른 사람이 그의 서명을
인하려면 우Git 소에 저PGP 개키를 내서 GPG키 데이터이스에 저한다.
$ git show maintainer-pgp-pub | gpg --import
사람들은 이개키를 어서 서명된 그를 인한다. 또한, 관리자가 시지에 서명을 인하는 방법을 적어
놓으면 좋다. `git show <tag>`으로 어떻게 서명된 그를 인하는지 명한다.
빌드넘버 만들기
Git'v123' 처럼 형태로 커이름을 만들지 않기 때문에 사람이 기하기 어렵다. 하지만 git describe
명령으로 좀 더 사람이 기하기 운 이름을 을 수 있다. Git은 가가까운 그의 이름과, 그에서 마나 더 커
161
였는지, 고 해당 커SHA-1 금 가다가 이름을 만든다.
$ git describe master
v1.6.2-rc1-20-g8c5b85c
게 사람이 을 수 있는 이름으로 스냅샷이나 드를 만든다. 소에서 Clone 한 후 소스코드로 Git
치하면 git --version 명령은 이게 생드넘버를 보여. 그가 달git describe 명령을
사용하면 다른 정보 없이 그 이름만 사용한다.
git describe 명령은 -a -s 옵션을 주고 만든 Annotated 그가 요하다. 릴리그는 git describe
명령으로 만드니까 이름이 적당한지 사전에 인해한다. 고 이 checkout이나 show 명령에도 사용할 수
있지만, 전적으로 이름 SHA-1 을 사용한다. 서 이 으로는 해당 커을 못 을 수도 있다. 최근 Linux
때문에 축약SHA-18자에서 10자로 늘어. 이제는 8자일 때 생성한 은 사용할 수 없다.
릴리즈 준비하기
배포할 릴리즈 버전이 비되었다. Git을 사용하지 않는 사람을 위해 소스코드 스냅샷한다. 쉽게 할 수
있도록 Gitgit archive 명령을 지원한다.
$ git archive master --prefix='project/' | gzip > `git describe
master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz
축 파일을 면 프로젝트의 가마지냅샷이 나온다. ZIP 형식으로 축 파일을 만들려면 --format=zip
옵션을 사용한다.
$ git archive master --prefix='project/' --format=zip > `git describe
master`.zip
한 스냅샷 파일은 웹사이트나 이일로 사람들에게 배포할 수 있다.
Shortlog 보기
일로 프로젝트의 경 사을 사람들에게 알려할 때, git shortlog 명령을 사용하면 지난 릴리즈 이후의
목록을 쉽게 수 있다. git shortlog 명령은 주어진 범위에 있는 커을 요. 아래최근 릴리
버전인 v1.0.1 이후의 커을 요해 주는 예제이다.
162
$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (8):
Ê Add support for annotated tags to Grit::Tag
Ê Add packed-refs annotated tag support.
Ê Add Grit::Commit#to_patch
Ê Update version and History.txt
Ê Remove stray `puts`
Ê Make ls_tree ignore nils
Tom Preston-Werner (4):
Ê fix dates in history
Ê dynamic version method
Ê Version bump to 1.0.2
Ê Regenerated gemspec for version 1.0.2
v1.0.1 이후 경 내용을 Author를 기으로 정한 커을 이일로 전송한다.
요약
이제 Git 프로젝트에 기여하고, 자신의 프로젝트를 운영하고, 다른 사람이 기여한 내용을 합하는 것 정도는 쉽게 할 수
있을 것이다. 쓸만한 Git 개발자가 된 것을 하한다. 다음 에서 Git을 호스팅하는 가대중적이고 가장 큰
서비스인 GitHub에 대해 살펴볼 것이다.
163
GitHub
GitHub은 가장 큰 Git 소 호스트이다. 수백만 개발자가 모여서 수백만 프로젝트를 수하는 중추다. Git 소를
GitHub에 만들어 운영하는 비율이 . 많은 오픈 소스 프로젝트는 GitHub을 이용해서 Git 호스팅, , 코드
, 등등의 일을 한다. Git을 많이 사용하다 보면 Git 프로젝트 자에는 참여하지 않더라도 GitHub하는
이 오거나 스스로 쓰고 어질 것이다.
GitHub쓰는 방법명한다. 계정을 생성해서 관리하는 방법, Git 소를 만들고 사용하는 방법,
프로젝트에 기여하거나 다른 사람의 기여를 받아들이는 방법, 프로그래밍 GitHub 인터이스, 으로
편하게 만드는 방법을 살펴.
프로젝트를 GitHub에 만들 생각이 없거나 GitHub에 있는 프로젝트에 참여할 생각이 없으면 그Git 로 넘어가도
된다.
인터이스는 변하는 거.
웹사이트의 UI는 시간에 따라 한다. GitHub 스크린샷들은 시간이 지나면 게 된다. 사실
하지 않고 으면 좋. 신 버전의 스크린샷이 포함된 버전을 다면 이 책의
온라인 버전을 어라. 마 거기좀 더 신 스크린샷이 적용있을 것이다.
계정 만들고 설정하기
장 먼저 할 일은 무사용자 계정을 만드는 일이다. https://github.com문해서 사용자이름과 이일 주소,
호를 입력하고 “Sign up for GitHub이라는 른다.
164
그림 82. GitHub 가입 .
다음 보이는 면은 유옵션에 대한 이지인데, 지금은 무시한다. GitHub는 입력한 이일 주소로 일을
을 것이다. 일의 지시를 따. 나중에 살펴볼 지만 이 과정은 우 중요하다.
계정도 GitHub 을 전부 사용할 수 있다. 한 가지 제이 있는데 모든 사람이 을 수 있는
개 프로젝트만 만들 수 있다. GitHub을 내면 비개 프로젝트도 만들 수 있지만, 이 책에서
명하지 않는다.
왼쪽 꼭대기에 있는 Octocat 로고를 하면 대시보드 이지로 이동한다. 이제 GitHub을 사용할 비가 된
것이다.
SSH 사용하기
이제는 https:// 프로토콜로도 Git 소를 사용하는 데 부함이 없다. 히 사용자이름과 호로 인만 하면
된다. 개 프로젝트를 Clone 하는 데는 인요 없다. 가 만든 계정은 프로젝트를 Fork 하고 그 프로젝트에
Push 할 때가 돼야 비로소 요하다.
SSH 모트를 쓰려면 개키를 정해한다. (아직 공개키가 없으면 SSH 개키 만들기를 참고) 아래 Windows
오른쪽 꼭대기에 있는 계정 크를 하자.
165
그림 83. “.
왼쪽 에서 “SSH keys” 선택한다.
그림 84. “SSH keys” .
여기서 “Add an SSH key” 한다. 키 이름을 적당히 입력하고 ~/.ssh/id_rsa.pub 일의 내용을 입력
사해 는다. “Add key” 한다.
SSH key 이름은 기하기 운 걸로 는다. "내 노트"이나 "회사 계정"분하기
이름으로 는다. 나중에 키를 제할 때 갈리지 않고 바로 알 수 있도록 는 것이 중요하다.
아바타
자동으로 생성해준 아바타를 다른 바타로 바수도 있다. “SSh Keys위에 있는 “Profile” 으로 가서 “Upload
new picture한다.
166
그림 85. “Profile” .
여기서는 여러분의 하드디스크에 있을 Git 로고를 선택하고 요한 만큼 자른다.
그림 86. 아바타 자.
167
이제부터 GitHub 사이트에서 어디에서든 사용자이름 바타가 보인다.
Gravatar 서비스에 바타를 로드 한 적이 있으면 자동으로 그 바타가 사용되고 지금 이 계를 요가 없다.
사용자 이메일 주소
GitHubGit 에 있는 이일 주소를 보고 어사용자인지 식별한다. 사용자가 이일 주소를 여러 개 사용해서
했어도 GitHub에 그 이일을 모등록하기만 했으면 GitHub한다. “Emails” 면에서 모등록한다.
그림 87. 이메일 주소 추가하기.
일 주소 추가하기.의 이일 주소는 각각 다른 상. 번째 주소는 이미 확인을 한 주(Primary) 주소이다.
이나 영수일은 주 주소로 간다. 두 번째 주소도 인한 주소로 주 주소로 경 할 수 있는 상. 마지주소는
아직 확인이 되어 주 주소로 경할 수 없다. 소의 커밋 메시지에 이 주소 세 개 중 하나라도 있으면 GitHub가 해당
사용자 계정 이지로 크를 걸어.
투팩터 인증
전한 보을 위해서 “2FA”(터 인)정한다. 2FA최근 들어 인기가 지는 인커니이다. 호를
았을 때 위하기 위해 사용한다. 2FA를 활성시키면 GitHub에 로그인 할 때 인가지
요하다(- 기존 로그인 방식OTPSMS를 추가). 둘 중 한 가지 방법려서는 자가 계정에 접할 수
없다.
2FA 면은 계정 이지의 Security 에 있다.
168
그림 88. Security 에 있는 2FA
“Set up two-factor authentication” 하면 2FA 이지로 이동한다. “TOTP(Time based One-Time
를 생성하는 스마트폰 앱을 사용하는 방식을 고거나 GitHub가 인코드를 SMS로 전송해주는 방식을 고를 수
있다. 정하면 로그인할 때 TOTP나 인코드가 요하다.
마음에 드는 인방법을 고고 지시에 따라 2FA정한다. GitHub에 로그인할 때마다 한 가지 코드를 더 입력해
한다. 이제 계정은 좀 더 전해.
GitHub 프로젝트에 기여하기
계정은 이제 만들었으니 프로젝트에 참여하는 방법을 살펴볼 차례가 됐다.
프로젝트 Fork 하기
참여하고 은 프로젝트가 생기면 마 그 프로젝트에 Push 한은 없을 니까 “Fork한다. “Fork하면
GitHub이 프로젝트를 통째사해. 은 사용자 네임이스에 있고 Push 할 수도 있다.
과거에는 “Fork가 좋은 의로 쓰이지 않았다. 오픈 소스 프로젝트를 “Fork한다는 것은 사해서
금은 다른 프로젝트를 만드는 것을 의했고 때때로 원프로젝트하거나 기여자를 나
과를 가오기도 했다. GitHub에서 “Fork순히 자신의 네임이스로 사하는 것을
한다. 개한 상로 수정하고 좀 더 열린 방식으로 참여할 수 있다.
방식에서는 사람들을 프로젝트에 추가하고 Push 한을 요가 없다. 사람들은 프로젝트를 “Fork해서 Push
한다. Push 경 내용을 원소로 보내 기여한다. 이것을 Pull Request라고 부는데 나중에 다시
명한다. 토론 드를 만들고 거기서 코드 를 하면서 토론하는 스드를 만들어 토론을 시작한다. 프로젝트 소유자
169
마음에 들 때까지 소유자기여자는 함께 토론한다. 마음에 들게 되면 Merge 한다.
프로젝트는 쉽게 Fork 할 수 있다. 프로젝트 이지를 문해서 오른쪽 꼭대기에 있는 “Fork한다.
그림 89. “Fork” 버튼.
사된 프로젝트 이지로 이동한다. 이 새 프로젝트의 소유자는 Fork 한 사람 자신이기 때문에 쓰기 한이
있다.
GitHub 플로우
GitHubPull Request가 중심인 협업 워크플로를 위주로 계됐다. 크플로는 Fork 해서 프로젝트에 기여하는
것인데 일 저소만 사용하는 작은 팀이나 전 세계에서 서 일하는 회사, 은 한 적 없는 사람들
사이에서도 유용하다. Git 브랜 에서 명했던 토픽 브랜 중심으로 일하는 방식이다.
아래와 같이 일한다.
1. 프로젝트를 Fork 한다.
2. master 으로 토픽 브랜치를 만든다.
3. 가 수정해서 커한다.
4. 자신의 GitHub 프로젝트에 브랜치를 Push 한다.
5. GitHubPull Request를 생성한다.
6. 토론하면서 그에 따라 계속 커한다.
7. 프로젝트 소유자는 Pull RequestMerge 하고 는다.
방식은 기적으로 Integration-Manager 크플로에서 명하는 Integration-Manager 크플로와 같. 토론이나
를 이일이 니라 GitHub에서 제하는 웹 기를 사용하는 것뿐이다.
GitHub에 있는 오픈소스 프로젝트에 이 크플로를 이용해서 가 기여하는 예제를 살펴보자.
Pull Request 만들기
Tony는 자신의 Arduino 치에서 실해볼 만한 코드를 고 있었고 GitHub에 있는 https://github.com/schacon/
blink에서 흡족한 프로그았다.
170
그림 90. 기여하고자 하는 프로젝트.
다 좋은데 빠르깜빡이는 게 마음에 들었다. 초 깜빡이는 것보다 3에 한 깜빡이는 게 더 좋을 것 았다.
서 프로그을 수정하고 원 프로젝트에 다시 보내기로 했다.
명했던 것처럼 'Fork' 해서 프로젝트를 사한다. 사용자 이름이 “tonychacon” 이라면
https://github.com/tonychacon/blink 에 프로젝트가 사된다. 이 프로젝트는 인 프로젝트이고 수정할 수
있다. 이 프로젝트를 로Clone 해서 토픽 브랜치를 만들고 코드를 수정하고 나서 GitHub에 다시 Push 한다.
171
$ git clone https://github.com/tonychacon/blink
Cloning into 'blink'...
$ cd blink
$ git checkout -b slow-blink
Switched to a new branch 'slow-blink'
$ sed -i '' 's/1000/3000/' blink.ino (macOS)
# If you're on a Linux system, do this instead:
# $ sed -i 's/1000/3000/' blink.ino
$ git diff --word-diff
diff --git a/blink.ino b/blink.ino
index 15b9911..a6cc5a5 100644
--- a/blink.ino
+++ b/blink.ino
@@ -18,7 +18,7 @@ void setup() {
// the loop routine runs over and over again forever:
void loop() {
Ê digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage
level)
Ê [-delay(1000);-]{+delay(3000);+} // wait for a second
Ê digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
Ê [-delay(1000);-]{+delay(3000);+} // wait for a second
}
$ git commit -a -m 'three seconds is better'
[slow-blink 5ca509d] three seconds is better
Ê1 file changed, 2 insertions(+), 2 deletions(-)
$ git push origin slow-blink
Username for 'https://github.com': tonychacon
Password for 'https://tonychacon@github.com':
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 340 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To https://github.com/tonychacon/blink
Ê* [new branch] slow-blink -> slow-blink
Fork 한 개인 저소를 로Clone 한다.
일인지 명이 되는 이름의 토픽 브랜치를 만든다.
코드를 수정한다.
는지 인한다.
172
토픽 브랜치에 커한다.
GitHub의 개인 저소에 토픽 브랜치를 Push 한다.
Fork 한 내 저소에 가면 GitHub토픽 브랜치가 하나 Push 됐다는 것을 알려주고 원 저소에 Pull Request를 보
수 있는 을 보여.
니면 저소의 브랜이지로(https://github.com/<user>/<project>/branches) 가서 해당
브랜치의 "New pull request" 을 이용한다.
그림 91. Pull Request 버튼
하면 Pull Request의 제목과 명을 입력하는 면이 보인다. 프로젝트 소유자가 판을 내
있을 정도로 을 들여 작성해한다. 수정했는지 마나 가치 있는지 명해서 관리자를 설득한다.
“ahead” 토픽 브랜치가 master 브랜치에서 달라도 보여주고 수정된 내용을 “unified diff” 형식으로
보여. 이 수정 내용이 프로젝트 관리자가 Merge 할 내용이다.
173
그림 92. Pull Request를 생하는 이지
면에 있는 'Create pull request' 하면 프로젝트 원소유자는 가 코드를 보다는 알는다.
에는 해당 Pull Request에 대한 모든 것을 보여주는 이지의 크가 들어 있다.
Pull Request는 보통 공개 프로젝트에서 사용한다. 기여자는 수정하고 나서 원 저소에 Pull
Request. 개발 기에는 프로젝트 내부에서도 많이 사용한다. Pull Request를 열어
놓은 토픽 브랜치라고 할지라도 계속 Push 할 수 있다. 마지니라 처음부터 Pull Request
열면 어주제를 가지고 팀 동료와 께 토론할 수 있어서 좋다.
Pull Request 놓고 감 놓고 배 놓기
Pull Request가 오면 프로젝트 소유자는 이 무엇인지 인한 후, Merge 은 거절하거나 코트를 달 수 있다.
소유자가 이디어 자를 마음에 들어 한다면 을 보기까지 좀 더 을 들여한다.
174
이런 소을 이일로 하는 크플로는 환경에서의 Git명했었다. GitHub에서는 온라인에서 한다. 프로젝트
소유자는 'unified diff' 형식경사하고 각 해당 라인에 코트를 달 수 있다.
그림 93. Pull Request드에 코멘
관리자가 코트를 달면 Pull Request를 만든 사람에게 알이 간다. 실제로는 저소를 'Watch’하는 사람 모에게
이 간다. 정책은 정할 수 있지만, 다음에 한다. Tony가 이일 알다면 이일 알
는다.
그림 94. 이메일 림으로 온 코멘
누구Pull Request에 코트를 달 수 있다. Pull Request 토론 페이지를 보면 프로젝트 소유자가 코드에 코트를
달거나 Pull Request 에 코트를 달면서 토론하는 것을 보여 . 코드 코트도 을 이루어 커뮤니할 수
있다.
175
그림 95. Pull Request 론 페이지
토론을 보고 기여자는 자신이 무엇을 해자신의 코드가 받아들여질지 알 수 있다. 직관적이다.
일을 이일로 하고자 한다면 관련 을 다시 말아스트에 다시 보내한다. 하지만, GitHub에서는 해당
토픽 브랜치에 이어서 커하고 Push 하면 된다. Pull Request에서 Push데이트한 PR의 코드를 보면 예전
코드에 달렸던 코트는 나오지 않는다. 추가된 커으로 인해 코드가 수정되었기 때문이다.
기존 PR에 이어서 Push를 하면 알이 가지 않는다. Tony는 자신이 작한 내용을 코트로 . 그러면
프로젝트 소유자는 무일이 있었는지 쉽게 알 수 있다.
176
그림 96. 최종 Pull Request
꼭 짚고 넘어가할 것이 있다. Pull Request“Files Changed” 하면 “unified” diff를 볼 수 있다.
Pull Request가 주 브랜치에 Merge 되면 어떻게 달라지는지 보여. git diff 명령을 표현하자면 `git diff
master…<branch>`와 같은 명령이 실되는 거고 `<branch>`Pull Request브랜치를 의한다. 내용인지
인하기에서 자세히 명한다.
그 외 알아두면 좋은 것은 GitHubPull RequestMerge 될 수 있는지 사해서 서버에서 Merge 할 수 있도록 Merge
을 제한다. 이 버은 저소에 쓰기 한이 있는 사람만 볼 수 있고 이 버으로 Merge 하면 Merge 이 생
(Trivial Merge). “fast-forward” Merge가 가할 때도 “non-fast-forwrd” Merge 한다.
177
Pull Request 브랜치를 당Merge 해도 된다. master 브랜치에 Merge 해서 GitHubPush 하면
자동으로 해당 Pull Request닫힌.
이런 방식이 대부분의 GitHub 프로젝트가 사용하는 기본 워크플로다. 토픽 브랜치를 만들고 Pull Request.
거기서 토론을 계속 하고 그 브랜치에 커을 하기도 한다. 마지에는 Merge하고 Request는다.
Fork는 옵션
한 저소의 두 브랜치를 고도 Pull Request를 열 수 있다. 한 저소에 쓰기 한이 있는 동
둘이서 어을 추가하려고 하고 있다면 토픽 브랜치를 만들고 Push 한다. 고 나서
소의 master 브랜치에 대해 Pull Request를 만들어 코드 와 토론을 시작한다. Fork
수가 니다.
Pull Request
GitHub에서 프로젝트에 기여하는 방법 중 가적인 방법을 살펴. Pull Request를 사용할 때 도움이 되는
유용한 가지 살펴보자.
PatchPull Request로 보내기
프로젝트에서는 Pull RequestPatch완벽하고 처럼 순서대로 적용돼야 한다고 생각하지 않는다.
스트를 사용하던 프로젝트에서는 Patch 순서가 의가 있다고 생각한다. GitHubPull Request는 어주제를
의하는 자. 의가 다 무으면 Merge 한다.
이는 우 중요하다. 적으로 처음부터 완벽한 코드를 보수 없어서 스트로 Patch를 보일은
없다. Pull Request기부터 프로젝트 관리할 수 있도록 해주기 때문에 는 게 니라
커뮤니티에서 함께 찾을 수 있다. Pull Request를 열면 관리커뮤니티는 어떻게 수정하는 게 좋을지 의
. Patch를 처음부터 다시 전를 작성하지 않도 된다. 수정한 만큼만 해당 브랜치에 커하고 하던 일과 대를 계속
해 나가면 된다.
Pull Request돌아가서 다시 보면 기여자가 커Rebase 하거나 Pull Request를 다시 열지 않았다는 것을
인할 수 있다. 기존 브랜치에 좀 더 커하고 Push 했을 뿐이다. 나중에 시간이 지나서 이 Pull Request를 다시
으면 이런 으로 정했는지에 대한 을 쉽게 알 수 있다. 웹사이트에서 “Merge” 누르Merge
을 일부러 다는 이 된다. Merge 에는 Pull Request 정보가 들어가기 때문에 요하면 제든지
인할 수 있다.
Pull Request를 최신으로 업데이트하기
Pull Request가 만든 지 오됐거나 깨끗하게 Merge 되지 않으면 가 쉽게 Merge 할 수 있게 수정한다.
GitHub은 자동으로 Merge 할 수 있는 Pull Request인지 Pull Request 이지 하에서 알려.
그림 97. 깨끗하게 Merge 할 수 없는 Pull Request
깨끗하게 Merge 할 수 없는 Pull Request 시지를 보면 해당 브랜치를 고으로 만든다.
고치지 않도 되도록 한다.
178
이 문제를 해하는 방법가지가 있다. 대상 브랜(master 브랜)를 기으로 Rebase 하는 방법이 있고
대상 브랜치를 Pull Request 브랜치에 Merge 하는 방법이 있다.
GitHub을 사용하는 개발자는 대부분 후자를 고른다. 서 살펴던 것과 은 이유다. Rebase 하면 히스토리
깨끗해지지만 훨씬 더 어렵고 에러 나기 쉽다.
Pull RequestMerge 될 수 있도록 대상 브랜치를 Merge 하려면 저 원 저소를 모트로 추가한다. 고 나서
Fetch 하고 그 저소의 대상 브랜치를 해당 토픽 브랜치에 Merge 한다. 문제를 해하고 그 브랜치에 도로 Push 한다.
“tonychacon” 예제에 이 크플로를 적용해보자. 원저자가 가 수정을 했는데 Pull Request이 난다. 여기부터
살펴보자.
$ git remote add upstream https://github.com/schacon/blink
$ git fetch upstream
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
From https://github.com/schacon/blink
Ê* [new branch] master -> upstream/master
$ git merge upstream/master
Auto-merging blink.ino
CONFLICT (content): Merge conflict in blink.ino
Automatic merge failed; fix conflicts and then commit the result.
$ vim blink.ino
$ git add blink.ino
$ git commit
[slow-blink 3c8d735] Merge remote-tracking branch 'upstream/master' \
Ê into slower-blink
$ git push origin slow-blink
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 682 bytes | 0 bytes/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To https://github.com/tonychacon/blink
Ê ef4725c..3c8d735 slower-blink -> slow-blink
원 저소를 “upstream이라는 이름의 모트로 추가한다
모트에서 신 데이터를 Fetch 한다
대상 브랜치를 토픽 브랜치에 Merge 한다
을 해한다
179
동일한 토픽 브랜치에 도로 Push 한다
게 하면 Pull Request는 자동으로 데이트되고 깨끗하게 Merge 할 수 있는지 재인된다.
그림 98. 깨끗하게 Merge 할 수 있는 Pull Request.
속성은 Git기 중 하나다. 오랫동무엇인가 만들고 있다면 신으로 유지하기 위해 대상 브랜치를 쉽게 Merge
수 있다. 다 마때까지 하고 또 하고 할 수 있다. Merge 할 때 발생하는 만 해하면 되고 지속적으로 개발
프로세스를 관리할 수 있다.
브랜치를 꼭 깨끗하게 유지하고 어서 Rebase 한다고 생각한다면 이열어 놓은 Pull Request에 대고 Push 하지
말아야 한다. 그럼 이 브랜치를 가Merge 해 놓은 사람들은 Rebase 의 위명했충격질 것이다.
대신 브랜치를 새로 만들어 Push 한다. Pull Request도 새로 여는데 원 Pull Request지 알 수 있도록 참
달고 원것은 는다.
참조
그럼 바로 어떻게 Pull Request를 참시키지?라는 의문이 들지만, 방법우 많다. GitHub에 쓰기 가
어디에서나 참를 달 수 있다.
IssuePull Request를 서로 참시키는 방법부터 살펴보자. 모든 Pull RequestIssue에는 프로젝트 내에서
유일한 호를 하나 할당한다. 예를 들어, 3Pull Request#3Issue는 동시에 있을 수 없다. `<num>`
형태로 코트가나 명에 Pull RequestIssue를 참수 있다. 방법일 프로젝트 위에서만 유효하다.
Fork 소의 IssuePull Request를 참시키려고 한다면 `username#<num>`라고 쓰고 예 다른 저소면
`username/repo#<num>`라고 써한다.
명을 위해 이미 브랜치를 Rebase 했고 Pull Request를 새로 만들었다고 하자. 그럼 예전 Pull Request지 알 수
있도록 새것에서 예전 것을 참하게 해보고 Pull Request의 상호 참.Fork 한 저소의 이예 다른
소의 이도 참하게 해보자.
180
그림 99. Pull Request의 상호 .
Pull Request를 보내면 Pull Request의 상호 참.처럼 보인다.
그림 100. Pull Request의 상호 .
GitHub URL을 전부 입력해도 요한 만큼으로 어든다.
고 원있던 Pull Request으면 새 Pull Request에는 기존 Pull Request닫혔다고 언급된다. GitHub
Pull Request 라인에 트백 이트를 자동으로 만든다. 서 이 Pull Request문하는 사람은 예전 Pull
Request닫혔는지 알 수 있고 그 크가 있어서 바로 해서 예전 것을 볼 수 있다. 크는 Pull Request
처럼 생.
181
그림 101. Pull Request의 트랙백
뿐만 니라 커SHA도 참할 수 있다. 40SHA를 적으면 GitHub은 자동으로 해당 커크를 걸어 .
Fork 소나 예 다른 저소의 커도 이슈와 동일한 방식으로 크시수 있다.
GitHub Flavored Markdown
다른 이크하는 것은 GitHub 쓰기의 걸음에 과하다. “GitHub Flavored Markdown이라는 형식으로
Pull Request, , 코드 주등에서 을 쓸 수 있다. Markdown 형식으로 을 쓰면 그스트로
쓴 글이지만 형식하고 된다.
GitHub Flavored Markdown 예제.Markdown으로 쓴 글이 어떻게 되는지 보여.
그림 102. GitHub Flavored Markdown .
GitHub Flavored Markdown
GitHub Flavored Markdown(이하 GFM)은 기Markdown확장했다. GFMPull Request나 이등의 을 쓸
우 유용하다.
182
타스크 리스트
GFM확장한 것 기중 타스크 스트가 있는데 Pull Request에서 사용하면 좋다. 해서 타스크 스트는
했다고 시할 수 있는 스의 목록이다. Pull Request에서 다 했다고 기하고 을 때 사용한다.
타스크 스트는 아래와 같이 사용한다.:
- [X] Write the code
- [ ] Write all the tests
- [ ] Document the code
이 타스크 스트를 이Pull Request에 사용하면 타스크 스트.처럼 된다.
그림 103. 타스크 리스트.
Pull RequestMerge 하기 전에 하는 일의 목록을 표현할 때 타스크 스트를 사용한다. Markdown
접 고치지 않고 스만 해도 해당 타스크가 됐다고 데이트되기 때문에 상당히 좋은 기이다.
GitHub은 이Pull Requests에 있는 타스크 스트를 계해서 목록 면에서 보여. 예를 들어, 타스크들이
Pull Request가 있으면 Pull Request 약 페이지에서 마나 진행됐는지 볼 수 있다. Pull Request
타스크 여러 개로 면 그 브랜치가 마나 진행됐는지 알기 쉽다. Pull Request 목록 면에서 보여주는 타스크
.를 보자.
그림 104. Pull Request 록 화면에서 보여주는 타스크 현.
Pull Request부터 열어 고 일을 하면 해당 기마나 진행됐는지 쉽게 알 수 있다.
코드 조각
트에 코드 각도 을 수 있다. 실제로 구현해서 브랜치에 커하기 전에 이디어를 코드로 표현해 볼 때 좋다.
그 외에도 순히 코드 예제를 보여주기 위해서 사용하거나 해당 Pull Request에서 구현한 것이 무엇인지 보여때도
183
사용한다.
으로 된 “Fence” 에 코드 각을 는다.
```java
for(int i=0 ; i < 5 ; i++)
{
Ê System.out.println("i is : " + i);
}
```
코드 각에 어 이름을 쓰면 GitHub강조(Syntax Highlight)도 해. 강조코드.
이름을 어서 강조과다.
그림 105. 강조로 미해진 .
인용
긴 글에서 한 부분만 어서 의하고 을 때 > 문자로 해당 부분을 인용하고 그 에 코트를 . 방법
히 사용하는 방법이라, 상당히 유용하고, 단축키도 지원한다. 인용하고 스트를 선택하고 r 키를 누르면 바로
트 상자에 해당 스트가 인용된다.
아래와 같이 인용한다.
> Whether 'tis Nobler in the mind to suffer
> The Slings and Arrows of outrageous Fortune,
How big are these slings and in particular, these arrows?
스트는 인용 예제.처럼 된다.
184
그림 106. 인용 .
Emoji
마지으로 소개하는 것은 Emoji을 수 있다는 것이다. EmojiGitHub Pull Request에서 정많이
사용된다. GitHubEmoji를 쉽게 사용할 수 있도록 는다. 트를 쓸 때 : 문자로 Emoji 입력을 시작하면 선택해서
자동성할 수 있도록 Emoji 목록을 보여.
그림 107. Emoji 자동완성.
Emoji:<name>: 형식으로 생. 아래 예제를 보자.
185
I :eyes: that :bug: and I :cold_sweat:.
:trophy: for :microscope: it.
:+1: and :sparkles: on this :ship:, it's :fire::poop:!
:clap::tada::panda_face:
되면 Emoji를 많이 쓴 글.처럼 보인다.
그림 108. Emoji를 많이 쓴 .
Emoji는 정보 전달하는 데도 좋지만 마나 재고 기표현도 가하다.
Emoji 문자를 사용하는 웹 서비스가 정많다. Emoji 문자가 있는지 쉽게 찾아볼 수 있는
치트시트가 있어서 고 참고할 수 있다.
http://www.emoji-cheat-sheet.com
이미지
GitHub이 제하는 에 이지를 포함시키는 기은 기적으로 GFM니지만 엄청 유용하다. Markdown
형식으로 이지를 부하고 을 때 일적인 방법으로는 이지를 올리고 그 URL찾아서 일일이 입력해하는데
. GitHub에서는 그지를 바로 Drag-and-Drop으로 을 수 있다.
186
그림 109. 어다 기로 이미지 자동 이기.
어다 놓기로 이지 자동 이기.돌아가서 보면 Text Area 위에 “Parsed As Markdown이라는 시를 볼 수 있다.
크를 하면 GitHub에서 Markdown을 어떻게 사용하는지 알려주는 치트시트를 보여.
GitHub 프로젝트 관리하기
지금까지 의 프로젝트에 기여하는 을 살펴보았고 이에는 접 프로젝트를 운영하는 을 살펴보자. 프로젝트를
생성해서 관리하는 방식 말이다.
새 저장소 만들기
소를 새로 만들고 프로젝트 코드를 유해 보자. 대시보드 오른에 있는 “New repository” 하면
소를 만드는 폼으로 이동한다. 바의 사용자이름 에 있는 + 해도 된다.
187
그림 110. “Your repositories” .
그림 111. 사용자이름 옆 “New repository” 메뉴.
위 버누르새 저를 만드는 면으로 이동한다.
188
그림 112. “새 저장소만들기.
프로젝트 이름을 는 것만 수다. 다른 것은 생해도 된다. “Create Repository” 하면 '하고
<user>/<project_name> 위치에 GitHub 소가 생.
아직 소에 코드가 하나도 없어서, GitHubGit 소를 만드는 방법이나 기존 Git 프로젝트를 방법
보여. 이 내용을 다시 살펴보고 다면 Git의 기를 보라. 여기서 또 명하지 않는다.
GitHub에 프로젝트를 렸으면 다른 사람들에게 프로젝트 URL을 알려주고 유할 수 있다. 모든 프로젝트의 HTTPS
URL`https://github.com/<user>/<project_name>`처럼 생SSH`
git@github.com:<user>/<project_name>`처럼 생. Git은 이 URL해서 Fetch 하고 Push 할 수 있지만,
방식은 사용하는 프로토콜에 따라 다.
GitHub 계정 없이 Clone 할 수 있기 때문에 개 프로젝트를 유할 때는 SSH보다 HTTP URL를 더
많이 유한다. SSH URL을 사용하려면 계정도 있어하고 SSH 키도 GitHub에 등록해한다.
라우저에서 프로젝트 이지에 접속할 때도 저URL로 사용하는 HTTP URL을 그대로
사용한다.
동료 추가하기
소에 커한을 주고 은 동가 있으면 “Collaborator” 로 추가해한다. BenJeff, Louise라는 동
있는데 그들이 내 저소에 Push 할 수 있도록 하고 으면 내 프로젝트에 GitHub 계정들을 추가해한다. 계정이
추가된 사람은 해당 프로젝트Git 소에 “Push” 할 수 있을 뿐만 니라 고 쓰기도 가하다.
오른쪽 밑에 있는 `Settings ` 크를 한다.
189
그림 113. 저장소 .
왼쪽 에서 “Collaborators” 선택한다. 스트 스에 사용자이름을 입력하고 “Add collaborator” 한다.
요한 사람을 모추가할 때까지 반복한다. 고 오른에 있는 “X” 하면 한이 회수된다.
그림 114. 저장소의 동.
Pull Request 관리하기
프로젝트를 만들고 코드도 고 동Push 할 수 있게 했다. 이제 Pull Request가 왔을 때 어떻게 해하는지 보자.
Pull Request은 저소나 Fork 한 저소에서 브랜치를 보내오는 것이다. 그 둘의 이는 한에 있다. Fork
소는 다른 사람의 저소이기 때문에 그 보내온 브랜치에 Push 한이 없다. 하지만, 은 저소의 브랜치에는
Push 할 수 있다.
“tonychacon” 이라는 사람이 “fade” 라는 Arduino 프로젝트를 만든 상을 살펴보자.
190
이메일 알림
사람이 코드를 수정해서 Pull Request를 보내왔다. 그러면 새로운 Pull Request가 왔다는 일이 당자에게 간다.
Pull Request에 대한 이일 알. 일이 보내.
그림 115. Pull Request에 대한 이메일 .
이 이일은 무엇이 달라것인지 간히 보여. 해당 Pull Request에서 어떤 파일이 마나 경됐는지 보여.
Pull Request 이지 크도 있고 CLIMerge 하는 방법URL도 간히 보여.
`git pull <url> patch-1`라는 명령이 금할 데 이게 하면 모트 브랜치를 간Merge 할 수 있다. 소를
모트로 추가하지 않도 된다. 요하면 토픽 브랜치를 만들고 모트 브랜치로부터 합하기에서 배운 명령어로 Pull
RequestMerge 해도 된다.
지만 .diff .patch URLPull Request'Unified DiffPatch 버전의 URL이다. URL
아래와 같Pull RequestMerge 할 수 있다.
$ curl http://github.com/tonychacon/fade/pull/1.patch | git am
Pull Request로 함께 일하기
GitHub 플로우에서 명했Pull Request를 만든 사람과 토론할 수 있다. GFM을 사용하여 특정 커선택하거나,
특정 라인을 지정하거나, 은 전Pull Request 에도 코트를 남길 수 있다.
191
에 참여하고 나면 가 코트할 때마다 이일 알이 계속 온다. 그 이일에는 Pull Request 이지의
크가 포함있기 때문에 어일이 일어나고 있는지 쉽게 알 수 있다. 일을 보내면 Pull Request
트로 달.
그림 116. 변 메일이 Pull Request의 스드가 .
보내온 코드가 마음에 들어서 Merge 하고 다면 로에 가져와Merge 할 수 있다. git pull <url> <branch>
명령으로 Merge 하면 되는데 Fork 한 저소를 모트로 추가하고 Fetch 해서 Merge 한다.
GitHub 사이트에서 “Merge” 누르는 것으로 간편하게 Merge 할 수 있다(Trivial Merge). “fast-forward”
할 때도 “non-fast-forward” Merge를 하기 때문에 Merge 이 생. “Merge해서
Merge 하면 Merge 이 생. 여기서 어떻게 해하는지 'command line' 크를 하면 Merge
Pull Request를 수동으로 Merge 하기.이 알려.
그림 117. Merge 버튼과 Pull Request를 수동으로 Merge 하기.
Pull RequestMerge 하지 않기로 했다면 그으면 된다. 그러면 그 Pull Request를 보사람에게 알
간다.
192
Pull RequestRef
일일이 모트를 등록하고 Pull 하는 것은 Pull Request를 많이 처하는 사람에게는 고. GitHub는 이
사용하는 방법을 제한다. 이 내용은 Refspec에서 자세히 명할 거고 금 어려수 있다.
GitHubPull Request브랜치를 서버에 있는 가상 브랜치로 노출해. GitHub가 자동으로 해주기 때문에 바로
이용하면 된다.
이걸 해보려면 저수(“plumbing”) 명령어인 ls-remote 요하다. 이 명령어는 일 쓰는 명령어는
니지만, 서버에 어Ref가 있는지 보여 . “plumbing” 명령어는 Plumbing 명령과 Porcelain 명령에서 자세히
명한다.
이 명령어로 좀 전의 “blink소를 살펴보자. 브랜치뿐만 니라 그 등 온Ref를 보여.
$ git ls-remote https://github.com/schacon/blink
10d539600d86723087810ec636870a504f4fee4d HEAD
10d539600d86723087810ec636870a504f4fee4d refs/heads/master
6a83107c62950be9453aac297bb0193fd743cd6e refs/pull/1/head
afe83c2d1a70674c9505cc1d8b7d380d5e076ed3 refs/pull/1/merge
3c8d735ee16296c242be7a9742ebfbc2665adec1 refs/pull/2/head
15c9f4f80973a2758462ab2066b6ad9fe8dcf03d refs/pull/2/merge
a5a7751a33b7e86c5e9bb07b26001bb17d775d1a refs/pull/4/head
31a45fc257e8433c8d8804e3e848cf61c9d3166c refs/pull/4/merge
이라면 git ls-remote origin 이라고 실도 된다. 모트 이름을 사용할 수 있다.
GitHub 소에 어Pull Request라도 열려있다면 refs/pull/ 로 시작하는 이름으로 Ref가 생성된다. 이것도
브랜치지만 refs/heads/ 로 시작하는 브랜는 달CloneFetch 할 때 받아지지 않으며 기적으로 무시된다.
Pull Request에는 Ref가 있다. /head 나는 것은 Pull Request 브랜치가 가키는 마지이다.
가 우소에 bug-fix 라는 브랜치를 Pull Request로 보내는 상을 살펴보자. 브랜치는 a5a775
. bug-fix 브랜치는 Fork 한 저소에 있는 브랜치라서 우소에 없다. 그럼에도 a5a775` 키는
`pull/<pr#>/head 형식브랜치가 자동으로 생. 매번 다른 저소를 모트로 등록하지 않고서도 Pull
Request 브랜치를 쉽게 Pull 할 수 있다.
브랜치를 한져와 보자.
$ git fetch origin refs/pull/958/head
From https://github.com/libgit2/libgit2
Ê* branch refs/pull/958/head -> FETCH_HEAD
모트의 브랜origin refs/pull/958/head Fetch 한다이다. Git실하게 전부 내려
마지.git/FETCH_HEAD 에 저한다. git merge FETCH_HEAD 으로 Merge 해서 스트할 수 있다.
Merge 하면 Merge 밋 메시지가 간 이상해. 또한 많은 Pull Request를 처하는 경우, 쓸데없는
Merge 도 많아진.
193
Pull Request전부 오게 할 수 있다. .git/config 일을 열어서 origin 모트를 는다. origin
모트는 사실 아래와 같은 것을 의한다.
[remote "origin"]
Ê url = https://github.com/libgit2/libgit2
Ê fetch = +refs/heads/*:refs/remotes/origin/*
fetch = 로 시작하는 라인이 “refspec” 이라는 거다. 모트 이름과 로.git 렉토리를 어떻게 하는지
나타. 여기서는 해당 모트에서 refs/heads 에 해당하는 이름이 refs/remotes/origin 렉토리
된다는 의. Refspec을 새로 추가해보자.
[remote "origin"]
Ê url = https://github.com/libgit2/libgit2.git
Ê fetch = +refs/heads/*:refs/remotes/origin/*
Ê fetch = +refs/pull/*/head:refs/remotes/origin/pr/*
추가한 마지라인의 의refs/pull/123/head Refrefs/remotes/origin/pr/123 에 저''
한다는 의. git fetch 라고 실하면 새 Refspec브랜치도 가온다.
$ git fetch
# …
Ê* [new ref] refs/pull/1/head -> origin/pr/1
Ê* [new ref] refs/pull/2/head -> origin/pr/2
Ê* [new ref] refs/pull/4/head -> origin/pr/4
# …
서버에 있는 모든 Pull Request을 추적하는 트브린치가 생. 쓰기는 하지만 계속 Fetch 수 있다.
게 하면 Pull Request를 로에 가져와서 작하는 게 편해.
$ git checkout pr/2
Checking out files: 100% (3769/3769), done.
Branch pr/2 set up to track remote branch pr/2 from origin.
Switched to a new branch 'pr/2'
head 나는 Refspec에 대해서 살펴고 이제 refs/pull/#/merge 처럼 생Refspec을 알보자. 브랜치는
GitHub에서 Merge 으로 Merge 했을 때 적용되는 과다. GitHub에서 실제로 Merge 하기 전에 로로 가져와
스트할 수 있다.
Pull Request 이어가기
Pull RequestMerge 브랜치는 master 니어도 된다. 브랜치를 고를 수도 있고 Pull Request를 열 때 다른
브랜치를 라도 된다. 심지어 다른 Pull Request를 고를 수도 있다.
착착 잘 진행하는 어Pull Request가 있는데 거기에 이디어를 더하고 다는 생각이 들었다. 좋은 이디어라는
194
신도 부하고 무엇보다 Merge 브랜치에 Push 한이 없다. Pull RequestPull Request를 보
있다.
Pull Request를 만들러 가면 이지 위에 어소의 브랜치를 어소의 브랜치로 요하는 것인지를
보여주는 스가 있다. “Edit” 누르Fork 한 저소 중 하나로 저소를 경하고 해당 저소의 브랜치로
경할 수 있다.
그림 118. Pull Request을 어디로 보지 대상을 선택.
쉽게 다른 Fork 소나 Pull Request브랜치를 Pull Request를 열 수 있다.
멘션과 알림
GitHub는 어팀이나 사람에게 질문하거나 드백을 을 수 있도록 쉽고 편한 알시스을 제한다.
GitHub 어디에서나 `@`만 입력해도 동나 기여자의 사용자이름이 자동성 된다.
그림 119. `@`만 입력.
자동에 없는 사람도 입력할 수 있지만, 자동성이 편하고 빠르.
195
GitHub에서 을 쓸 때 `@`을 하면 해당 사용자에게 알이 간다. 일일이 의으러 다니는 것보다 이
토론에 참여시키는 게 훨씬 유용하다. GitHub에서는 으로 팀의 동나 다른 사람을 이Pull Request
참여시.
`@`으로 언급되면 그 사람은 구독 (Subscribed)” 가 된다. 서 해당 이Pull Request에서 계속
이 온다. Pull Request접 만들었거나, 해당 저소를 'Watching’하는 상이거나, 트를
경우에도 구독 가 된다. 더는 알지 않으면 면의 “Unsubscribe” 으로 출 수 있다.
그림 120. 정 이Pull Request(Unsubscribe).
알림 페이지
GitHub은 프로젝트에서 어일이 일어나면 바로 알 수 있도록 내해 주는 것이다. 이 알은 원하는 방법으로
정해 쓸 수 있다. 정의 “Notification center에 가면 정할 수 있는 옵션이 있다.
196
그림 121. Notification center 옵션.
을 이일로 을지 웹으로 을지 선택할 수 있다. 물론 두 가지 방법을 동시에 사용해도 된다. 고 그
참여하는 경우프로젝트를 'Watching' 하는 경우를 나선택할 수 있다.
웹 알림
웹 알GitHub에서 제하는 것으로 GitHub 사이트에서만 인할 수 있다. 옵션선택하면 알이 오면 알
파란 점을 볼 수 있다. Notification center.인해보자.
그림 122. Notification center.
하면 알시지를 인할 수 있다. 은 프로젝트로 분된다. 왼쪽 에 있는 프로젝트를
선택하면 관련 만 걸러서 볼 수 있다. 각 알에 있는 스를 해서 었다고 시를 할 수 있고 제일 위에 있는
197
스를 하면 해당 알에 대해서 전부 시를 할 수 있다. 'Mute' 하면 해당 사
대해서는 더는 알이 오지 않는다.
이 기을 사용하면 지는 알들도 우 효율적으로 처할 수 있다. GitHub파워 유저는 이일 알놓고
GitHub 사이트에서만 알관리하기도 한다.
이메일 알림
일 알놓으면 이일로도 GitHub 인할 수 있다. 일 알으로 온 코Pull Request
대한 이일 알.의 예를 보면 관련 들이 이일 스드로 되는 것을 볼 수 있다. 서 이일 스드를
지원하는 라이트를 사용하는 것이 좋다.
GitHub가 보더를 보면 여러 가지 타데이터가 들어 있다. 서 사용자는 이터나 룰 같은 자동 관리
으로 쉽게 관리할 수 있다.
Pull Request에 대한 이일 알.에서 보여일의 더는 아래와 같.
To: tonychacon/fade <fade@noreply.github.com>
Message-ID: <tonychacon/fade/pull/1@github.com>
Subject: [fade] Wait longer to see the dimming effect better (#1)
X-GitHub-Recipient: tonychacon
List-ID: tonychacon/fade <fade.tonychacon.github.com>
List-Archive: https://github.com/tonychacon/fade
List-Post: <mailto:reply+i-4XXX@reply.github.com>
List-Unsubscribe: <mailto:unsub+i-XXX@reply.github.com>,...
X-GitHub-Recipient-Address: tchacon@example.com
프로젝트에 따라 Pull Request인지에 따라 분하거나 다른 주소로 재전송하고 다면 Message-ID 를 이용하는
게 좋다. 이 데이터는 <user>/<project>/<type>/<id> 형식으로 있다. 에 대한 데이터면
`<type>`부분이 “pull” 니라 “issues” 라고 있을 것이다.
List-Post List-Unsubscribe 드를 인하는 라이트를 사용하고 있으면 좀 더 편하게 사용할 수
있다. List-Post 는 이일로 스트에 올리는 데 사용하고 List-Unsubscribe 는 이라이트에서
을 그만 도록 할 수 있다. 슈와 Pull Request이지의 “Unsubscribe” 하거나 웹 알이지에서
“Mute하는 것과 .
일과 웹 알이 둘 다 있으면 알이 이일로도 오고 웹으로도 온다. 라이트에서 이지가 용되어
있으면, 일을 었을 때 웹에서도 었다고 시된다.
특별한 파일
소에 있는 일 중에서 GitHub가 사용하는 가지 특이한 일들이 있다.
README
GitHub는 저이지를 보여README 일을 이용해서 보여. README 형식에 상없이
보여. README 일이든 README.md 일이든 README.asciidoc 일이든 GitHub가 자동으로 해서
보여.
198
많은 사람이 이 일에 저소나 프로젝트에 처음 문한 사람들에게 요한 정보를 정. 통 아래와 같은 내용을
.
프로젝트인지
정하고 치하는 방법
사용과 실행 결과에 대한 예제
프로젝트의 라이
기여하는 방법
GitHubREADME 일을 하는 것이기 때문에 이지나 외부 크를 적어도 된다.
CONTRIBUTING
GitHubCONTRIBUTING 일도 인한다. README가지로 원하는 형식을 사용하면 된다. Pull
Request를 열 때 이 일이 있으면 CONTRIBUTING 일이 있음을 보여.크를 보여.
그림 123. CONTRIBUTING 파일이 있음을 보여.
일에는 프로젝트에 기여하는 방법Pull Request 규칙 같은 것을 적는다. 그러면 사람들이 Pull Request를 열 때
이 가이드라인을 참고할 수 있다.
프로젝트 관리
관리할 만한 게 로 없지만 알고 있으면 유용한 것들을 소개한다.
기본 브랜치 변경하기
본 브랜치를 “master” 고 다른 브랜치로 정할 수 있다. Pull Request를 열 때 정한 기본 브랜치가 기으로
선택된다. 본 브랜치는 저이지의 “Options에서 경한다.
199
그림 124. 브랜치 변경하기.
본 브랜경은 쉽고 정로 기으로 쓰인다. 소를 Clone 하면 여기서 정한 브랜치가 기으로
Checkout된다.
프로젝트 넘기기
프로젝트 소유자를 다른 사용자나 Organization으로 경할 수 있다. 이지의 “Options” 을 보면 이지
아래“Transfer ownership목이 있다. 여기 있는 Transfer 으로 프로젝트를 넘수 있다.
그림 125. 다른 GitHub 사용자나 Organization에 프로젝트 기기.
던 프로젝트를 다른 사람에게 넘주거나 프로젝트가 커Organizaiton 계정으로 기고 을 때 유용하다.
소만 옮겨지는 것이 니라 'Watching’하는 사람이나 'Star’한 사람까지도 함옮겨. URL
Redirect되는데 웹 접속뿐만 니라 Clone 이나 Fetch 까지도 Redirect된다.
Organization 관리하기
GitHub에는 Organization이라는 계정도 있다. 개인 계정처럼 Organizaiton 계정도 프로젝트 네임이스지만 다른
이 많다. 이 계정은 여러 명이 은 프로젝트를 관리하는 데 사용하는 그계정이고 사람들을 서을 나
관리하는 도도 있다. 이 계정은 “perl” 이나 “rails” 은 오픈소스 그이나 “google” 이나 “twitter” 은 회사가
사용한다.
200
Organization 기초
Organization을 만드는 것은 우 쉽다. GitHub 이지 오른위에 있는 “+” 하고 에서 “New
organization선택하면 된다.
그림 126. “New organization” 메뉴 아이템.
저 이름과 소유자 이일 주소를 입력해서 Organization 계정을 만든다. 고 나서 다른 사람들을 대한다.
요하면 동 소유자로 만들 수 있다.
다 만들면 Organization의 소유자가 된다. 개인 계정과 마가지로 Organization도 오픈 소스에는 무.
GitHubOrganization 소유자가 저소를 Fork 할 때는 어느 계정으로 Fork 하는 것인지 는다. 새 저소를 만들
때도 개인 계정 에 만들지 Organization 에 만들지 선택할 수 있다. 고 소유자는 해당 Organization에 저소가
때마다 자동으로 “Watching” 가 된다.
바타에서 개인 바타를 렸던 것처럼 Organization 계정에도 똑같바타를 올릴 수 있다. 계정 이지도
개인 계정과 . 가지고 있는 저소의 목록 이지가 이지이고 다른 사람들이 볼 수 있다.
Organization 계정이 개인 계정과 다른 이 있는데 그 들을 살펴보자.
Organization과 개인은 팀을 연결된다. Organization의 사용자소는 팀으로 관리되고 저소의 정도
팀으로 관리한다.
회사에 frontend, backend, deployscripts 게 저소가 세 개 있다고 하자. HTML/CSS/JavaScript
개발자는 frontend 소에 접한이 있어한다. 대로 운영하는 사람들은 backend deployscripts
은 저소에 접한이 있어한다. Organization에서 팀은 저소에서 함일하는 사람을 관리하는 효과적인
.
Organization 이지는 저, 사용자, 팀을 한에 보여주는 대시보드다.
201
그림 127. Organization 이지
Organization 이지 오른에 있는 'Teams' 사이드바를 하면 팀을 관리하는 이지로 넘어간다. 다음 이지에서
팀에 팀원이나 저소를 추가하고, 정을 관리하고, 팀의 정을 할 수 있다. 팀은 저소에 대해 기 전용,
쓰기, 관리 한을 가질 수 있다. 이지.에 있는 “Settings” 하면 한 수경할 수 있다.
그림 128. 이지.
가를 팀에 대하면 그 사람에게 일이 간다.
202
개인 사용자에 하는 것처럼 팀 @mentions 도 사용할 수 있다. @acmecorp/frontend 처럼 하면 팀의 모든
버가 참여하게 된다. 누구테 물할지 모를 때는 그팀 전에 문의하는 것도 방법이다.
사용자가 속하는 팀의 수는 제한이 없다. 순히 팀을 관리 용도로 사용하지 마라. ux, css, refactoring
팀은 어질문 등을 관리하기에 좋고 legal, colorblind 은 팀은 또 다른 이를 처하는 데 좋다.
감사 로그
소유자는 Organization에서 일어나는 모든 정보를 알 수 있다. 'Audit Log' 에 보면 저소에서 일어난 일들의 로그가
있다. 가 세계 어디에서 무일을 했는지 보여.
그림 129. 사 로그.
203
소유자는 이 면에서 , 어디서, 무엇을 했는지 걸러 볼 수 있다.
GitHub 스크
지금까지 GitHub의 주요기크플로를 모살펴. 프로젝트가 크거나 그이 크면 꼼꼼하게 정하거나
다른 서비스를 합시요도 있다.
GitHub에는 해커들에게 제하는 방법이 있다. 이 절에서는 GitHub API을 사용하는 명한다.
서비스와 훅
GitHub 관리과 서비스 절에 보면 다른 시스동하는 가방법이 나온다.
서비스
GitHub 서비스부터 살펴보자. 과 서비스는 저소의 이지에서 동할 수 있다. 이전에 동를 추가하거나 기
브랜치를 정하던 그이다. “WebhooksServices” 서비스와 훅 설.처럼 생.
그림 130. 서비스와 훅 설정 화면.
CI, 버그 트, , , 문서 시스등과 동하는 데 사용하는 서비스가 수있다. 여기서는 가
순한 Email 을 살펴. “Add Service” 에서 “email” 선택하면 Email 서비스 . 면으로
이동한다.
204
그림 131. Email 서비스 .
일을 입력하고 “Add service” 누르가 저소에 Push 할 때마다 이일이 날아간다. 서비스는 다
트를 처할 수 있지만, Push 할 때 그 데이터를 가지고 가를 한다.
동하려는 시스을 지원하는 서비스가 이있는지 GitHub에서 찾아한다. 예를 들어, Jenkins를 사용해서
코드 스트할 계이라면 Jenkins 서비스를 이용해서 동한다. 가 저소에 Push 할 때마다 스트를 수되도록
할 수 있다.
GitHub 서비스에 없는 사이트나 외부 서비스와 연동하고 거나 좀 더 세세한 정을 하고 으면 GitHub 을 이용한다.
GitHub 소의 순하다. URL을 하나 주면 그 URLHTTP 이로드를 보내.
GitHub 훅 페이로드를 처하는 간한 웹 서비스를 하나 만들고 그 서비스에 원하는 동작을 구현하는 것이 일적이다.
서비스와 훅 설.“Add webhook하면 아래와 같훅 설. 이지로 이동한다.
205
그림 132. 훅 설.
훅 설정은 우 간하다. URL키를 입력하고 “Add webhook한다. 트의 이로드가
요한 것인지도 선택할 수 있지만 push 트의 이로드만 보내는 것이 기이다. 브랜치에나
코드를 Push 하면 HTTP 이로드가 전송된다.
을 처하는 간한 웹 서비스 예제를 하나 살펴보자. 이 웹서비스는 Ruby 웹 프레임워크인 Sinatra를 사용했다.
하기 때문에 무엇을 하는 웹 서비스인지 쉽게 이해할 수 있을 것이다.
일을 보내는 서비스를 만들어 보자. 이 서비스는 가 어느 브랜치에 어떤 파일을 Push 했는지를 알려. 이런
서비스는 우 간하게 만들 수 있다.
206
require 'sinatra'
require 'json'
require 'mail'
post '/payload' do
Ê push = JSON.parse(request.body.read) # parse the JSON
Ê # gather the data we're looking for
Ê pusher = push["pusher"]["name"]
Ê branch = push["ref"]
Ê # get a list of all the files touched
Ê files = push["commits"].map do |commit|
Ê commit['added'] + commit['modified'] + commit['removed']
Ê end
Ê files = files.flatten.uniq
Ê # check for our criteria
Ê if pusher == 'schacon' &&
Ê branch == 'ref/heads/special-branch' &&
Ê files.include?('special-file.txt')
Ê Mail.deliver do
Ê from 'tchacon@example.com'
Ê to 'tchacon@example.com'
Ê subject 'Scott Changed the File'
Ê body "ALARM"
Ê end
Ê end
end
GitHubPush 했는지, 어느 브랜치에 Push 했는지, Push 한 커에서 어떤 파일을 수정했는지에 대한 정보를
JSON 이로드에 담아서 보. 여기서는 특정 사해서 만할 때만 이일을 보.
GitHub는 개발하고 스트할 때 사용하는 개발자 콘솔도 제한다. 콘솔정한 이지에 있다. 콘솔에서 해당
최근 히스토리 몇 개를 인할 수 있다. 데이터가 전송됐는지 인할 수 있다. 전송에 성했으면 요
응답의 바디더를 모두 확인할 수 있다. 이것으로 을 쉽게 스트하고 디버할 수 있다.
207
그림 133. 디버정보.
서비스를 스트할 수 있도록 히스토리에 있는 이로드를 재전송할 수 있다.
트가 있고 각각 어떻게 웹을 만드는지가 자세히 알고 다면 GitHub 개발 문서를 참고하라.
(https://developer.github.com/webhooks/)
GitHub API
208
서비스와 훅은 저소에서 발생한 이트의 알방법이다. 그런데 이트의 정보를 좀 더 자세히 알고 으면,
자동으로 동를 추가하거나 이을 달도록 하고 으면, 좋은 방법이 없을까?
이런 일을 위해서 GitHub API있다. GitHub가 제하는 API Endpoint우 많서 웹사이트에서 하는
만한 일은 자동할 수 있다. 이 절에서는 인하고 API연결하고, 에 코트하고, Pull Request의 상
경하는 을 배운다.
기본 사용법
요하지 않은 API EndpointGET 을 보내기가 가쉽다. 사용자 정보나 오픈 소스 프로젝트의 정보를
어오는 것들이 이에 해당한다. 아래처럼 요을 보내면 “schacon” 이라는 사용자에 대해 자세히 알 수 있다.
$ curl https://api.github.com/users/schacon
{
Ê "login": "schacon",
Ê "id": 70,
Ê "avatar_url": "https://avatars.githubusercontent.com/u/70",
# …
Ê "name": "Scott Chacon",
Ê "company": "GitHub",
Ê "following": 19,
Ê "created_at": "2008-01-27T17:19:28Z",
Ê "updated_at": "2014-06-10T02:37:23Z"
}
Organization, 프로젝트, , 정보를 가오는 Endpoint가 많이 있다. GitHub 이지에서 볼 수 있는
것은 다 된다. 심지어 Markdown하거나 .gitignore 릿을 제하는 API도 있다.
$ curl https://api.github.com/gitignore/templates/Java
{
Ê "name": "Java",
Ê "source": "*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see
http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
"
}
209
에 코멘트하기
Pull Request에 코트를 달거나 개하지 않은 정보를 으려고 할 때는 인요하다.
가지 방법으로 인할 수 있다. 사용자이름과 호가 요한 Basic 도 가하지만, 개인 세스 토큰을 사용하는 게
. 이지의 “Applications” 에서 생성할 수 있다.
그림 134. 이지의 “Applications” 에서 엑세스 토을 생.
토큰을 어디에 쓸지 위를 선택하고 명을 입력한다. 나중에 스크트나 을 더이상 사용하지 않게 되었을
, 제를 편히 할 수 있도록 명 이해하기 쉽게 다는 게 좋다.
토큰이 생성되면 사해서 사용한다. 이제 스크트에서 사용자이름과 호를 사용하지 않고 이 토큰을 사용할 수 있다.
토큰용하는 위가 제한있고 제든지 기할 수 있어서 좋다.
을 하지 않으면 API 사용 수 제한이 . 을 하지 않으면 한 시간에 60용되지만, 을 하면 한
시간에 5,000까지 용된다.
이제 이에 코트를 달보자. #6 에 코트를 달 거다.
repos/<user>/<repo>/issues/<num>/comments 형식URLPOST 을 보내는데 'Authorization'
더에 생성한 토큰어서 함.
210
$ curl -H "Content-Type: application/json" \
Ê -H "Authorization: token TOKEN" \
Ê --data '{"body":"A new comment, :+1:"}' \
Ê https://api.github.com/repos/schacon/blink/issues/6/comments
{
Ê "id": 58322100,
Ê "html_url": "https://github.com/schacon/blink/issues/6#issuecomment-
58322100",
Ê ...
Ê "user": {
Ê "login": "tonychacon",
Ê "id": 7874698,
Ê "avatar_url": "https://avatars.githubusercontent.com/u/7874698?v=2",
Ê "type": "User",
Ê },
Ê "created_at": "2014-10-08T07:48:19Z",
Ê "updated_at": "2014-10-08T07:48:19Z",
Ê "body": "A new comment, :+1:"
}
해당 이슈 페이지에 가면 코트를 인할 수 있다. GitHub API.처럼 .
그림 135. GitHub API로 쓴 코멘.
웹사이트에서 할 수 있는 일은 전부 API로도 할 수 있다. 마일스을 만들고 정하기, 사람들에게 이Pull Request
할당하기, 을 만들고 수정하기, 데이터 사용하기, 을 하거나 브랜치 만들기, Pull Request를 만들고
Merge 하기, 팀을 만들고 수정하기, Pull Request 코드에 코트하기, 사이트에서 하기 등 다 된다.
Pull Request의 상태 변경하기
가 살펴볼 마지예제는 Pull Request한 것인데 히 유용하다. 은 하나 이상의 상를 가질 수 있는데
API해서 상를 추가하거나 회할 수 있다.
대부분의 CI스팅 서비스들은 코드가 시되면 바로 스트를 하고 나서 이 API를 사용한다. 이 모든 스트를
과하면 포트한다. API로 커밋 메시지가 규칙게 작성됐지 포트할 수 있다. 코드를 보사람이 제대로
가이드라인을 지는지나 커에 제대로 서명했는지도 기록할 수 있다.
밋 메시지에 Signed-off-by 라는 스트이 있는지 사하는 웹 서비스를 만들어 보자. 저 저소에 이 웹
서비스를 호출하는 웹을 등록한다.
211
require 'httparty'
require 'sinatra'
require 'json'
post '/payload' do
Ê push = JSON.parse(request.body.read) # parse the JSON
Ê repo_name = push['repository']['full_name']
Ê # look through each commit message
Ê push["commits"].each do |commit|
Ê # look for a Signed-off-by string
Ê if /Signed-off-by/.match commit['message']
Ê state = 'success'
Ê description = 'Successfully signed off!'
Ê else
Ê state = 'failure'
Ê description = 'No signoff found.'
Ê end
Ê # post status to GitHub
Ê sha = commit["id"]
Ê status_url =
"https://api.github.com/repos/#{repo_name}/statuses/#{sha}"
Ê status = {
Ê "state" => state,
Ê "description" => description,
Ê "target_url" => "http://example.com/how-to-signoff",
Ê "context" => "validate/signoff"
Ê }
Ê HTTParty.post(status_url,
Ê :body => status.to_json,
Ê :headers => {
Ê 'Content-Type' => 'application/json',
Ê 'User-Agent' => 'tonychacon/signoff',
Ê 'Authorization' => "token #{ENV['TOKEN']}" }
Ê )
Ê end
end
이 웹서비스는 로 어렵지 않다. Push 하면 모든 커는데, 밋 메시지에서 Signed-off-by 스트
는다. 과의 상`/repos/<user>/<repo>/statuses/<commit_sha>`라는 Endpoint 주소에 POST
으로 보.
의 상'success', 'failure', 'error’일 수 있다. 의 상(state)와 설(description), 자세한 정보를 인할 수
있는 URL(target_url), 분하는 컨텍스트(context)” 를 함전송한다. 일 커에서도 다한 경우가 있기
때문에, 컨텍스트가 요하다. 예를 들어 유효성을 검증하거나 상을 제해 주는 스팅 서비스의 경우 상
212
하는데, “컨텍스트드를 해 어떻게 상변화했는지를 알 수 있다.
을 적용하고 나서 Pull Request를 새로 열면 API기한 커.은 상태 메시지를 보게 된다.
그림 136. API로 표기한 커밋 상.
“Signed-off-by” 스트이 있는 커밋 메시지에는 색 체이 달고 그지 않은 커에는 'X' 시가
. Pull Request의 상는 마지의 상를 보여주는데 상'failure’면 경고해. API
사용해서 스트 과를 Pull Request포트하는 것은 우 유용하다. 스트에 실하는 커Merge 하는 일을
미연지할 수 있다.
Octokit
이 책에서는 순한 HTTP 을 보기 때문에 curl 만 사용했다. 하지만, 더 편하게 API를 사용할 수 있게 해주는
오픈소스 라이가 있다. 이 책을 쓰는 시에서는 GoObjective-C, Ruby, .NET을 지원한다. 자세한 정보는
http://github.com/octokit에 가서 인하면 되고 이많은 기을 지원한다.
이 도로 프로젝트가 요하는 대로 GitHub크플로를 할 수 있다. API에 대한 구체적인 문서
가이드는 https://developer.github.com에서 인해한다.
요약
이제 GitHub 사용자가 됐다. 계정을 생성하는 방법, Organization을 만드는 방법, 소를 만들고 Push 하는 방법,
다른 사람의 프로젝트에 참여하는 방법, 다른 사람의 참여를 받아들이는 방법을 배. 다음 에서는 Git의 전지전
복잡한 상나가는 방법을 살펴. 정한 Git 고수가 될 수 있을 것이다.
213
Git
지금까지 일상적으로 자주 사용하는 명령들과 가지 크플로를 배. 일을 추적하고 커하는 등의 기적인
명령뿐만 니라 Staging Area좋은지도 배고 가토픽 브랜치를 만들고 Merge 하는 방법도 다. 이제는
Git 소로 분히 소스코드를 관리할 수 있을 것이다.
에서는 일상적으로 사용하지는 않지만 위한 상에서 드시 요한 Git 를 살펴.
리비전 조회하기
Git은 커하나를 가키거나 위를 사용하여 여러 커을 가키는 다방법고 있다. 그 많은 방법는 것이
요하않지만 알아두면 좋다.
리비전 하나 가리키기
40자나 되는 긴긴 SHA-1 해시 으로도 커을 외수 있지만 사람이 사용하기 좋은 방법이 있다. 이 절에서는 커
키거나 표현하는 방법가지 명한다.
SHA-1
Git은 해시 몇 글자만으로도 어인지 분히 식별할 수 있다. 에서 해시 이 중되지 않으면 해시
4자만으로도 나타수 있다. SHA-1 이라고 해도 유일해한다.
git log 명령으로 어이 있는지 회하는 예제를 보자.
$ git log
commit 734713bc047d87bf7eac9674765ae793478c50d3
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Jan 2 18:32:33 2009 -0800
Ê fixed refs handling, added gc auto, updated tests
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 15:08:43 2008 -0800
Ê Merge commit 'phedders/rdocs'
commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 14:58:32 2008 -
Ê added some blame and merge stuff
위의 내용은 1c002dd… 로 시작하는 커에 대해 로그를 살펴보다는 이다. git show 명령을 사용하는 다음 과는
두 같(은 해시 이 다른 커과 중되지 않다고 가정).
214
$ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
$ git show 1c002dd4b536e7479f
$ git show 1c002d
git log 명령에 --abbrev-commit 이라는 옵션을 추가하면 고 중되지 않는 해시 을 보여. 으로
7자를 보여주고 해시 이 중되는 경우 더 해시 을 보여.
$ git log --abbrev-commit --pretty=oneline
ca82a6d changed the version number
085bb3b removed unnecessary test code
a11bef0 first commit
8자에서 10자 내외로도 분히 유일하게 커을 나타수 있다. 20186프로젝트인 Linux
79만 개 이상의 커, 650만 개 이상의 오젝트가 있다. Linux 프로젝트는 해시 11개만 사용해도 이 없다.
SHA-1 해시 에 대한
Git을 쓰는 사람들은 가성이 작하지만 SHA-1 이 중될까 봐 걱정한다.
되면 어일이 벌어질까?
있는 SHA-1 Git 데이터이스에 커되면 새로운 개라고 해도 이된 것으로
생각하고 이전의 커을 재사용한다. 서 해당 SHA-1 의 커Checkout 하면 상 처음
한 커Checkout 된다.
그러나 해시 이 중되는 일은 일어나기 어렵다. SHA-1 의 크기는 20 바이트(160비트)이다. 해시
이 중50%가 되는 데 요한 개의 수는 2
80
이다. 이 수는 12,000(''
'- 10
24
, 돌 확하는 공식p = (n(n-1)/2) * (1/2^160) )이다. ,
존재하는 모알의 수에 1,200한 수와 맞는다.
아직SHA-1 해시 이 중될까 봐 걱정하는 사람들을 위해 좀 더 . 에서 6
5천만 명의 인가 개발하고 각자 Linux 히스토리 체와(650만 개) 는 개
내고 바로 Push 한다고 가정하자. 이런 상에서 해시 돌 날 확50%가 되기까지는
2년이 걸. 어느 가 한 순간에 모대에게 훨씬 .
브랜치로 가리키기
을 가키는 방법 중에 가많이 사용하는 방법이 있다. 브랜치의 가장 최신 커이라면 간브랜
이름으로 커을 가리킬 수 있다. 브랜치 이름을 Git 명령에 전달하면 브랜치가 가키는 커을 가키게 된다.
topic1 브랜치의 최근 을 보고 으면 아래와 같이 실한다. topic1 브랜치가 ca82a6d… 를 가키고 있기
때문에 명령의 과는 .
$ git show ca82a6dff817ec66f44342007202690a93763949
$ git show topic1
브랜치가 가키는 개SHA-1 에 대한 rev-parse 이라는 Plumbing 가 해. Git
215
내부에서 이 에 대해 시원하게 명한다. 적으로 rev-parse 은 저수명령이기 때문에 소에는 전
요하지 않다. 도 한사용해보고 어떤 결과가 나오는지 알아 두.
$ git rev-parse topic1
ca82a6dff817ec66f44342007202690a93763949
RefLog로 가리키기
Git은 자동으로 브랜HEAD가 지난 달 동에 가리켰었던 커을 모기록하는데 이 로그를 “Reflog” 라고
부른다.
git reflog 를 실하면 Reflog를 볼 수 있다.
$ git reflog
734713b HEAD@{0}: commit: fixed refs handling, added gc auto, updated
d921970 HEAD@{1}: merge phedders/rdocs: Merge made by the 'recursive'
strategy.
1c002dd HEAD@{2}: commit: added some blame and merge stuff
1c36188 HEAD@{3}: rebase -i (squash): updating HEAD
95df984 HEAD@{4}: commit: # This is a combination of two commits.
1c36188 HEAD@{5}: rebase -i (squash): updating HEAD
7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD
Git브랜치가 가키는 것이 달라질 때마다 그 정보를 시 영에 저한다. 서 예전에 가키던 것이 무엇인지
인해 볼 수 있다. @{n} 규칙을 사용하면 아래와 같HEAD5전에 가리켰던 것을 알 수 있다.
$ git show HEAD@{5}
순서뿐 니라 시간도 사용할 수 있다. 어제 master 브랜치를 보고 으면 아래와 같이 한다.
$ git show master@{yesterday}
이 명령은 어제 master 브랜치가 가키고 있던 것이 무엇인지 보여. Reflog남아있을 때만 회할 수 있기 때문에
무 오된 커회할 수 없다.
git log -g 명령을 사용하면 git reflog 과를 git log 명령과 형태로 볼 수 있다.
216
$ git log -g master
commit 734713bc047d87bf7eac9674765ae793478c50d3
Reflog: master@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: commit: fixed refs handling, added gc auto, updated
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Jan 2 18:32:33 2009 -0800
Ê fixed refs handling, added gc auto, updated tests
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Reflog: master@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: merge phedders/rdocs: Merge made by recursive.
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 15:08:43 2008 -0800
Ê Merge commit 'phedders/rdocs'
Reflog의 일은 모의 일이기 때문에 내 Reflog가 동의 저소에는 있을 수 없다. 이제 Clone 한 저소는
무것도 한 것이 없어서 Reflog가 하나도 없다. git show HEAD@{2.months.ago} 은 명령은 적어도 달 전에
Clone 한 저소에서나 사용할 수 있다. 그러니까 이 명령을 5분 전에 Clone 한 저소에 사용하면 과도 나오지
않는다.
ReflogGitShell의 명령 히스토리 버전으로 생각하기
UnixLinux 사용 경이 있는 경우 reflogGitShell의 명령 히스토리 버전으로 생각해볼 수 있다.
여기서 중요한 은 오나의 에서만 인할 수 있는 내용이라는 으로 은 시스에 있더라도 다른이
유되지 않는 정보라는 이다.
계통 관계로 가리키기
통 관계로도 커표현할 수 있다. 이름 ^ () 기호를 이면 Git은 해당 커의 부모를 는다. 프로젝트
히스토리아래와 같을 때는 아래처럼 한다.
$ git log --pretty=format:'%h %s' --graph
* 734713b fixed refs handling, added gc auto, updated tests
* d921970 Merge commit 'phedders/rdocs'
|\
| * 35cfb2b Some rdoc changes
* | 1c002dd added some blame and merge stuff
|/
* 1c36188 ignore *.gem
* 9b29157 add open3_detach to gemspec file list
HEAD^ 는 바로 “HEAD의 부모를 의로 바로 이전 커을 보여.
217
$ git show HEAD^
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 15:08:43 2008 -0800
Ê Merge commit 'phedders/rdocs'
Windows에서 기호 사용하기
Windows에서 실cmd.exe 에서는 ^ 기호가 이다른 의로 사용되고 있어서 Git 에서 사용하려면 좀 다른
방식을 사용해한다. 기호 개를 속으로 사용하거나 표 안에서 사용해한다.
$ git show HEAD^ # will NOT work on Windows
$ git show HEAD^^ # OK
$ git show "HEAD^" # OK
^ 자도 사용할 수 있다. 예를 들어 d921970^2 “d921970두 번째 부모를 의한다. 두 번째 부모가
있는 Merge 에만 사용할 수 있다. 번째 부모는 Merge 할 때 Checkout 했던 브랜치를 하고 두 번째 부모는
Merge 한 대상 브랜치를 의한다.
$ git show d921970^
commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 14:58:32 2008 -0800
Ê added some blame and merge stuff
$ git show d921970^2
commit 35cfb2b795a55793d7cc56a6cc2060b4bb732548
Author: Paul Hedderly <paul+git@mjr.org>
Date: Wed Dec 10 22:22:03 2008 +0000
Ê Some rdoc changes
표현하는 방법으로 ~ 라는 것도 있다. HEAD~ HEAD^ 똑같번째 부모를 가. 하지만,
자를 사용하면 달라. HEAD~2 는 명령을 실할 시번째 부모의 번째 부모” , 부모를 가.
위의 예제에서 HEAD~3 아래와 같.
218
$ git show HEAD~3
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date: Fri Nov 7 13:47:59 2008 -0500
Ê ignore *.gem
이것은 HEAD
^
와 같표현이다. 부모의 부모의 부모 부모.
$ git show HEAD^^^
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date: Fri Nov 7 13:47:59 2008 -0500
Ê ignore *.gem
두 표현이 사용할 수도 있다. 위의 예제에서 HEAD~3^2 를 사용하면 부모의 Merge 의 부모의 부모를
회한다.
위로 커밋 가리키기
을 하나씩 조회할 수도 있지만, 위를 주고 여러 커을 한꺼번회할 수도 있다. 위를 사용하여 회할 수
있으면 브랜치를 관리할 때 유용하다. 상당히 많은 브랜치를 가지고 있고 브랜치들은 아직도 주 브랜치에 Merge
되고 ?” 라는 의문이 들면 위를 주고 어떤 브랜치인지 쉽게 을 수 있다.
Double Dot
위를 표현하는 문으로 Double Dot(..)을 많이 . Double Dot은 어들이 한에는 관련됐고 다른 에는
관련되지 않았는지 Git에게 어보는 것이다. 예들 들어 위를 명하는 데 사용할 예제은 커히스토리가 있다고
가정하자.
그림 137. 범위를 명하는 데 사용할
experiment 브랜치의 커들 중에서 아직 master 브랜치에 Merge 하지 않은 것들만 보고 으면
master..experiment 라고 사용한다. 표현“master에는 없지만, experiment에는 있는 커을 의한다.
여기에서는 명을 쉽게 하려고 실제 과가 니라 그의 커을 의하는 문자를 사용한다.
219
$ git log master..experiment
D
C
대로 experiment 에는 없고 master 에만 있는 커금하면 브랜치 순서를 거로 사용한다.
experiment..master experiment 에는 없고 master 에만 있는 것을 알려.
$ git log experiment..master
F
E
experiment 브랜치를 Merge 할 때마다 Merge 하기 전에 무엇이 경됐는지 인해보고 을 것이다. 모트
소에 Push 할 때도 마가지로 인해보고 을 것이다. 히 유용하다.
$ git log origin/master..HEAD
이 명령은 origin 소의 master 브랜치에는 없고 Checkout 중인 브랜치에만 있는 커을 보여.
Checkout 브랜치가 origin/master 라면 git log origin/master..HEAD 가 보여주는 커Push 하면
서버에 전송될 커들이다. 고 한Refs를 생하면 GitHEAD`라고 가정하기 때문에 `git log
origin/master.. git log origin/master..HEAD 와 같.
세 개 이상의 Refs
Double Dot은 간하고 유용하지만 개 이상의 브랜치에는 사용할 수 없다. 그러니까 재 작중인 브랜치에는
있지만 다른 여러 브랜치에는 없는 커을 보고 으면 .. 으로는 인할 수 없다. Git^ 이나 --not 옵션 뒤브랜
이름을 으면 그 브랜치에 없는 커찾아준. 아래의 명령 세 가지는 모두 같은 명령이다.
$ git log refA..refB
$ git log ^refA refB
$ git log refB --not refA
옵션들은 Double Dot으로는 할 수 없는, 세 개 이상의 Refs에 사용할 수 있는 장점이 있다. 예를 들어 refA refB
에는 있지만 refC 에는 없는 커을 보려면 아래 중 한 명령을 사용한다.
$ git log refA refB ^refC
$ git log refA refB --not refC
용하면 작중인 브랜다른 브랜치을 우 상세하게 비해볼 수 있다.
220
Triple Dot
Triple Dot에 있는 Refs 사이에서 공통으로 가지는 것을 제외하고 서로 다른 커만 보여. 위를 명하는
데 사용할 예제의 커히스토리를 다시 보자. master experiment 공통부분은 빼고 다른 커만 보고
으면 아래와 같이 하면 된다.
$ git log master...experiment
F
E
D
C
log 명령의 과를 최근 날순으로 보여. 이 예제에서는 커개 보여.
log 명령에 --left-right 옵션을 추가하면 각 커이 어느 브랜치에 속하는지도 보여주기 때문에 좀 더
이해하기 쉽다.
$ git log --left-right master...experiment
< F
< E
> D
> C
와 같은 명령을 사용하면 원하는 커을 좀 더 꼼꼼하게 살펴볼 수 있다.
화형 명령
여기서 소개하는 가지 대화형 명령을 이용하면 바로 전문가처럼 능숙하게 커할 수 있다. 스크트를 해 커
일을 고고 수정된 일의 일부분만 커할 수도 있다. 스크트는 수정하는 일이 우 많통째로 커하기
어려때 이슈별로 나서 커하기에 좋다. 슈별로 나서 커하면 함일하는 동하기 워진.
git add 명령에 -i --interactive 옵션을 주고 실하면 Git아래와 같은 대화형 모드로 들어간다.
$ git add -i
Ê staged unstaged path
Ê 1: unchanged +0/-1 TODO
Ê 2: unchanged +1/-1 index.html
Ê 3: unchanged +5/-1 lib/simplegit.rb
*** Commands ***
Ê 1: status 2: update 3: revert 4: add untracked
Ê 5: patch 6: diff 7: quit 8: help
What now>
이 명령은 Staging Area재 상가 어떻고 할 수 있는 일이 무엇인지 보여. 적으로 git status 명령이
221
보여주는 것과 지만 좀 더 간하고 정있다. 왼쪽에는 Staged 일들을 보여주고 오른에는 Unstaged
일들을 보여.
고 마지“Commands” 부분에서는 할 수 일이 무엇인지 보여. 일들을 Stage하고 Unstage하는 것,
Untracked 일들을 추가하는 것, Stage일을 Diff할 수 있다. 게다가 수정한 일의 일부분만 Staging
Area에 추가할 수도 있다.
Staging Area에 파일 추가하고 추가 소하기
What now> 프트에서 2 u (update) 입력하면 Staging Area에 추가할 수 있는 일을 전부 보여.
What now> 2
Ê staged unstaged path
Ê 1: unchanged +0/-1 TODO
Ê 2: unchanged +1/-1 index.html
Ê 3: unchanged +5/-1 lib/simplegit.rb
Update>>
TODO` `index.html 일을 Stage 하려면 아래와 같이 입력한다.
Update>> 1,2
Ê staged unstaged path
* 1: unchanged +0/-1 TODO
* 2: unchanged +1/-1 index.html
Ê 3: unchanged +5/-1 lib/simplegit.rb
Update>>
* 시가 일은 Stage 하도록 선택한 것이다. 선택하고 Update>> 프트에 무것도 입력하지 않고 터를
치면 Git선택일을 Staging Area로 추가한다.
Update>>
updated 2 paths
*** Commands ***
Ê 1: status 2: update 3: revert 4: add untracked
Ê 5: patch 6: diff 7: quit 8: help
What now> 1
Ê staged unstaged path
Ê 1: +0/-1 nothing TODO
Ê 2: +1/-1 nothing index.html
Ê 3: unchanged +5/-1 lib/simplegit.rb
이제 TODO` `index.html 일은 Stage했고 simplegit.rb 일만 아직 Unstaged 남아 있다. 이제
TODO 일을 다시 Unstage 하고 으면 3 이나 r (revert) 입력한다.
222
*** Commands ***
Ê 1: status 2: update 3: revert 4: add untracked
Ê 5: patch 6: diff 7: quit 8: help
What now> 3
Ê staged unstaged path
Ê 1: +0/-1 nothing TODO
Ê 2: +1/-1 nothing index.html
Ê 3: unchanged +5/-1 lib/simplegit.rb
Revert>> 1
Ê staged unstaged path
* 1: +0/-1 nothing TODO
Ê 2: +1/-1 nothing index.html
Ê 3: unchanged +5/-1 lib/simplegit.rb
Revert>> [enter]
reverted one path
다시 status선택하면 TODO 일이 Unstaged 인 것을 알 수 있다.
*** Commands ***
Ê 1: status 2: update 3: revert 4: add untracked
Ê 5: patch 6: diff 7: quit 8: help
What now> 1
Ê staged unstaged path
Ê 1: unchanged +0/-1 TODO
Ê 2: +1/-1 nothing index.html
Ê 3: unchanged +5/-1 lib/simplegit.rb
Staged 일들의 경내용을 보려면 6 이나 d (diff) 입력한다. 그러면 Staged 일들을 보여.
그중에서 일 하나를 선택한다. 과는 커드라인에서 git diff --cached 라고 실와 같.
223
*** Commands ***
Ê 1: status 2: update 3: revert 4: add untracked
Ê 5: patch 6: diff 7: quit 8: help
What now> 6
Ê staged unstaged path
Ê 1: +1/-1 nothing index.html
Review diff>> 1
diff --git a/index.html b/index.html
index 4d07108..4335f49 100644
--- a/index.html
+++ b/index.html
@@ -16,7 +16,7 @@ Date Finder
Ê<p id="out">...</p>
-<div id="footer">contact : support@github.com</div>
+<div id="footer">contact : email.support@github.com</div>
Ê<script type="text/javascript">
와 같이 대화형 추가 모드를 사용하면 Staging Area일들을 좀 더 쉽게 추가할 수 있다.
파일의 일부분만 Staging Area에 추가하기
일의 일부분만 Staging Area에 추가하는 것도 가하다. 예를 들어 simplegit.rb 일은 고부분이 데이다.
그 중 하나를 추가하고 나지는 그대로 . Git에서는 이런 작우 쉽게 할 수 있다. 화형 프트에서 5, p
(patch) 입력한다. 그러면 Git은 부분적으로 Staging Area에 추가할 일이 있는지 는다. 일을 선택하면 일의
특정 부분을 Staging Area에 추가할 것인지 부분분하여 는다.
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index dd5ecc4..57399e0 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -22,7 +22,7 @@ class SimpleGit
Ê end
Ê def log(treeish = 'master')
- command("git log -n 25 #{treeish}")
+ command("git log -n 30 #{treeish}")
Ê end
Ê def blame(path)
Stage this hunk [y,n,a,d,/,j,J,g,e,?]?
여기에서 ? 를 입력하면 선택할 수 있는 명령을 명해.
224
Stage this hunk [y,n,a,d,/,j,J,g,e,?]? ?
y - stage this hunk
n - do not stage this hunk
a - stage this and all the remaining hunks in the file
d - do not stage this hunk nor any of the remaining hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
y n 을 입력하면 각 부분을 Stage 할지 정할 수 있다. 하지만, 일을 통째Stage 하거나 요할 때까지
그대로 는 것이 다음부터 더 유용할지도 모른다. 일의 어부분은 Stage 하고 다른 부분은 Unstaged
놓고 status 명령으로 인해보면 과는 아래와 같.
What now> 1
Ê staged unstaged path
Ê 1: unchanged +0/-1 TODO
Ê 2: +1/-1 nothing index.html
Ê 3: +1/-1 +4/-0 lib/simplegit.rb
simplegit.rb 일의 상를 보자. 라인은 Staged 이고 어라인은 Unstaged라고 알려것이다.
일의 일부를 Stage 했다. 이제 대화형 모드를 하고 일부분만 Stage 일을 커할 수 있다.
화형 스크트로만 일 일부분을 Stage 할 수 있는 것은 니다. git add -p git add --patch 로도
일을 할 수 있다.
git reset --patch 명령을 사용해서 일 일부만 Stage Area에서 내수 있다. , git checkout --patch
를 사용해서 일 일부를 다시 Checkout 을 수 있다. git stash save --patch 명령으로는 일 일부만 Stash
할 수 있다. 각 명령에 대해서 더 자세히 알보자
StashingCleaning
당신이 어프로젝트에서 한 부분을 당하고 있다고 하자. 고 여기에서 가 작하던 일이 있고 다른 요
들어브랜치를 경해할 일이 생다고 치자. 그런데 이런 상에서 아직 하지 않은 일을 커하는 것이
끄럽다는 것이 문제다. 하지 않고 나중에 다시 돌아와서 작을 다시 하고 을 것이다. 이 문제는 git stash
라는 명령으로 해할 수 있다.
Stash 명령을 사용하면 렉토리에서 수정한 일들만 저한다. StashModified이면서 Tracked 일과
Staging Area에 있는 일들을 보소다. 아직 내지 않은 수정사을 스시 저했다가 나중에 다시
적용할 수 있다(브랜치가 달라이다).
225
git stash push 로의 이동
201710Git 스트에는 엄청의가 있었습니다. 의는 git stash save
명령을 은시키고 git stash push` 하는 내용에 대한 것이었습니다. `git
stash push 명령의 경우 pathspec 으로 선택하여 Stash하는 옵션이 추가되었는데 git stash
save 명령이 지원하지 못하는 것이었습니다.
git stash save 명령이 바로 제되는 것은 니기에 아직 이 명령을 쓰는 것에 대해 정할
요는 없지만 git stash push 명령으로 대하는 것에 대해 생각해볼 요가 있습니다.
일을 Stash 하기
예제 프로젝트를 하나 살펴보자. 일을 개 수정하고 그 중 하나는 Staging Area에 추가한다. git status
명령을 실하면 아래와 같과를 볼 수 있다.
$ git status
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê modified: index.html
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: lib/simplegit.rb
이제 브랜치를 경해 보자. 아직 중인 일은 커할 게 니라서 모Stash 한다. git stash git stash
save 를 실하면 스에 새로운 Stash가 만들어.
$ git stash
Saved working directory and index state \
Ê "WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")
대신 렉토리깨끗.
$ git status
# On branch master
nothing to commit, working directory clean
이제 브랜치나 라서 쉽게 바수 있다. 수정하던 것을 스에 저했다. 아래와 같git stash list
226
사용하여 저Stash인한다.
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
Stash 개는 원있었다. 세 개의 Stash를 사용할 수 있다. 이제 git stash apply 를 사용하여
Stash를 다시 적용할 수 있다. git stash 명령을 실하면 Stash를 다시 적용하는 방법도 알려서 편하다. `git
stash apply stash@{2}`처럼 Stash 이름을 입력하면 라서 적용할 수 있다. 이름이 없으면 Git은 가장 최근Stash
적용한다.
$ git stash apply
On branch master
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: index.html
Ê modified: lib/simplegit.rb
no changes added to commit (use "git add" and/or "git commit -a")
GitStash에 저할 때 수정했던 일들을 원해. 원할 때의 렉토리Stash 할 때의 그 브랜치이고
렉토리깨끗한 상였다. 하지만 꼭 깨끗렉토리Stash 할 때와 같브랜치에 적용해하는 것은 니다.
떤 브랜치에서 Stash 하고 다른 브랜치로 기고서 거기에 Stash원할 수 있다. 렉토리깨끗
요도 없다. 렉토리에 수정하고 커하지 않은 일들이 있을 때도 Stash를 적용할 수 있다.
있으면 알려.
GitStash를 적용할 때 Staged 였던 일을 자동으로 다시 Staged 로 만들어 주지 않는다. git
stash apply 명령을 실할 때 --index 옵션을 주어 Staged 까지 적용한다. 래야 하던 상
돌아올 수 있다.
227
$ git stash apply --index
On branch master
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê modified: index.html
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: lib/simplegit.rb
apply 옵션순히 Stash를 적용하는 것뿐이다. Stash는 여전히 스남아 있다. git stash drop 명령을
사용하여 해당 Stash를 제거한다.
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)
git stash pop 이라는 명령도 있는데 이 명령은 Stash를 적용하고 나서 바로 스에서 제거해.
Stash를 만드는 새로방법
Stash를 만드는 방법은 여러 가지다. 주로 사용하는 옵션으로 stash save 명령과 이 쓰는 --keep-index 이다.
옵션을 이용하면 이Staging Area에 들어 있는 일을 Stash 하지 않는다.
$ git status -s
M index.html
ÊM lib/simplegit.rb
$ git stash --keep-index
Saved working directory and index state WIP on master: 1b65b17 added the
index file
HEAD is now at 1b65b17 added the index file
$ git status -s
M index.html
추적하지 않는 일과 추적 중인 일을 Stash 하는 일도 하다. 적으로 git stash 는 추적 중인 일만
한다. 추적 중이지 않은 일을 이 저하려면 Stash 명령을 사용할 때 --include-untracked -u 옵션
228
.
$ git status -s
M index.html
ÊM lib/simplegit.rb
?? new-file.txt
$ git stash -u
Saved working directory and index state WIP on master: 1b65b17 added the
index file
HEAD is now at 1b65b17 added the index file
$ git status -s
$
으로 --patch 옵션이면 Git은 수정된 모든 사을 저하지 않는다. 대신 대화형 프트가 경된 데이터
중 저할 것과 저하지 않을 것을 지정할 수 있다.
$ git stash --patch
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 66d332e..8bb5674 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -16,6 +16,10 @@ class SimpleGit
Ê return `#{git_cmd} 2>&1`.chomp
Ê end
Ê end
+
+ def show(treeish = 'master')
+ command("git show #{treeish}")
+ end
Êend
Êtest
Stash this hunk [y,n,q,a,d,/,e,?]? y
Saved working directory and index state WIP on master: 1b65b17 added the
index file
Stash를 적용한 브랜치 만들기
Stash에 저하면 한동그대로 유지한 로 그 브랜치에서 계속 새로운 일을 한다. 그러면 이제 저Stash
적용하는 것이 문제가 된다. 수정한 일에 Stash를 적용하면 이 일어수도 있고 그러면 또 을 해한다.
요한 것은 Stash 한 것을 쉽게 다시 스트하는 것이다. git stash branch <브랜> 명령을 실하면 Stash
당시의 커Checkout 한 후 새로운 브랜치를 만들고 여기에 적용한다. 이 모든 것이 성하면 Stash제한다.
229
$ git stash branch testchanges
M index.html
M lib/simplegit.rb
Switched to a new branch 'testchanges'
On branch testchanges
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê modified: index.html
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: lib/simplegit.rb
Dropped refs/stash@{0} (29d385a81d163dfd45a452a2ce816487a6b8b014)
이 명령은 브랜치를 새로 만들고 Stash원해주는 우 편한 도.
디렉토리 청소하기
하고 있던 일을 Stash 하지 않고 순히 그 일들을 치을 때가 있다. git clean 명령이 그 일을
한다.
Merge나 외부 도가 만들어낸 파일을 지우거나 이전 드 작으로 생성된 각일을 지우는 데 요하다.
이 명령을 사용할 때는 신중해한다. 이 명령을 사용하면 렉토리 안의 추적하고 있지 않은 모든 일이 지지기
때문이다. 명령을 실하고 나서 후회해도 소용없다. 워진 파일은 돌아오지 않는다. git stash –all 명령을
이용하면 지우는 똑같지만, 저 모든 일을 Stash 로 좀 더 전하다.
렉토리불필요한 일들을 전부 지우려면 git clean 을 사용한다. 추적 중이지 않은 모든 정보를
렉토리에서 지우고 다면 git clean -f -d 명령을 사용하자. 이 명령은 하위 디렉토리까지 모. -f
옵션(force)의 의이며 "로 그해라"라는 이다.
이 명령을 실했을 때 어일이 일어미리 보고 다면 -n 옵션을 사용한다. -n 옵션가상으로 실해보고 어
일들이 지질지 알려달라라는 이다.
$ git clean -d -n
Would remove test.o
Would remove tmp/
git clean 명령은 추적 중이지 않은 일만 지우는 게 기동작이다. .gitignore 에 명시했거나 해서 무시되는
일은 지우지 않는다. 무시된 일까지 함지우려면 -x 옵션요하다. .o 일까지도 지
있다.
230
$ git status -s
ÊM lib/simplegit.rb
?? build.TMP
?? tmp/
$ git clean -n -d
Would remove build.TMP
Would remove tmp/
$ git clean -n -d -x
Would remove build.TMP
Would remove test.o
Would remove tmp/
git clean 이 무슨 짓을 할지 신이 들 때는 -n 옵션여서 저 실해보자. clean 명령을 대화형으로
하려면 -i 옵션이면 된다.
화형으로 실clean 명령의 모습은 아래와 같.
$ git clean -x -i
Would remove the following items:
Ê build.TMP test.o
*** Commands ***
Ê 1: clean 2: filter by pattern 3: select by numbers
4: ask each 5: quit
Ê 6: help
What now>
화형으로 실하면 일마다 지우지 정하거나 특정 으로 걸러서 지수도 있다.
하던 저소가 전 지저분해Git에게 제로 정하도록 해하는 경우가 생
있다. 예를 들어 Git 버전관리 데이터가 포함된 디렉토리사해왔거나 서렉토리에 문제가
거나 하는 경우 git clean -fd 옵션으로 실한 명령이라도 디렉토리 제가 되지 않는
경우가 있다. 이런 경우에는 -f 옵션을 한더 사용하여 제성을 추가로 주어한다.
내 작업에 서명하기
Git적으로 전하다. 하지만, 되는 니다. 소에 무나 접하지 못하게 하고 인된
사람에게서만 커으려면 GPG를 이용한다.
GPG 소개
선 뭔가를 서명 하려면, GPG 정도 하고 개인키도 치해한다.
231
$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub 2048R/0A46826A 2014-06-04
uid Scott Chacon (Git signing key) <schacon@gmail.com>
sub 2048R/874529A9 2014-06-04
키가 없으면 키를 새로 만들어한다. 키를 만들려면 gpg --genkey 명령을 실한다.
$ gpg --gen-key
서명에 사용할 수 있는 개인키가 이있다면 Git 정 중에 user.signingkey 정해서 사용할 수 있다.
$ git config --global user.signingkey 0A46826A
정하고 나면 이제 Git에 서명할 때 등록한 키를 사용한다.
태그 서명하기
GPG 개인키 정을 마으면 새로 만드는 그들에 서명할 수 있다. 서명하려면 -a 대신 -s 만 쓰면 된다.
$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Ben Straub <ben@straub.cc>"
2048-bit RSA key, ID 800430EB, created 2014-05-04
그를 git show 명령으로 보면, GPG 서명이 어 있는 걸 볼 수 있다.
232
$ git show v1.5
tag v1.5
Tagger: Ben Straub <ben@straub.cc>
Date: Sat May 3 20:29:41 2014 -0700
my signed 1.5 tag
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAABAgAGBQJTZbQlAAoJEF0+sviABDDrZbQH/09PfE51KPVPlanr6q1v4/Ut
LQxfojUWiLQdg2ESJItkcuweYg+kc3HCyFejeDIBw9dpXt00rY26p05qrpnG+85b
hM1/PswpPLuBSr+oCIDj5GMC2r2iEKsfv2fJbNW8iWAXVLoWZRF8B0MfqX/YTMbm
ecorc4iXzQu7tupRihslbNkfvfciMnSDeSvzCpWAHl7h8Wj6hhqePmLm9lAYqnKp
8S5B/1SSQuEAjRZgI4IexpZoeKGVDptPHxLLS38fozsyi0QyDyzEgJxcJQVMXxVi
RUysgqjcpT8+iQM1PblGfHR4XAhuOqN5Fx06PSaFZhqvWFezJ28/CLyX5q+oIVk=
=EFTF
-----END PGP SIGNATURE-----
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
Ê changed the version number
태그 확인하기
git tag -v <tag-name> 명령을 이용해 그에 서명한 사람이 정그 사람이 는지 인한다. 이 명령은 서명을
인하기 위해 GPG를 사용한다. 인 작을 하려면 서명한 사람의 GPG 개키를 키 관리 시스에 등록해한다.
$ git tag -v v1.4.2.1
object 883653babd8ee7ea23e6a5c392bb739348b1eb61
type commit
tag v1.4.2.1
tagger Junio C Hamano <junkio@cox.net> 1158138501 -0700
GIT 1.4.2.1
Minor fixes since 1.4.2, including git-mv and git-http with alternates.
gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Good signature from "Junio C Hamano <junkio@cox.net>"
gpg: aka "[jpeg image of size 1513]"
Primary key fingerprint: 3565 2A26 2040 E066 C9A7 4A7D C0C6 D9A4 F311
9B9A
서명한 사람의 개키가 없으면 아래와 같시지가 나타난다.
233
gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Can't check signature: public key not found
error: could not verify the tag 'v1.4.2.1'
커밋에 서명하기
신 버전(v1.7.9 이상)Git은 커에도 서명할 수 있다. 에 서명하고 으면 git commit 명령에 -S 옵션
여주면 된다.
$ git commit -a -S -m 'signed commit'
You need a passphrase to unlock the secret key for
user: "Scott Chacon (Git signing key) <schacon@gmail.com>"
2048-bit RSA key, ID 0A46826A, created 2014-06-04
[master 5c3386c] signed commit
Ê4 files changed, 4 insertions(+), 24 deletions(-)
Êrewrite Rakefile (100%)
Êcreate mode 100644 lib/git.rb
서명을 인하려면 git log 명령에 --show-signature 옵션여주자.
$ git log --show-signature -1
commit 5c3386cf54bba0a33a32da706aa52bc0155503c2
gpg: Signature made Wed Jun 4 19:49:17 2014 PDT using RSA key ID 0A46826A
gpg: Good signature from "Scott Chacon (Git signing key)
<schacon@gmail.com>"
Author: Scott Chacon <schacon@gmail.com>
Date: Wed Jun 4 19:49:17 2014 -0700
Ê signed commit
git log 로 출력한 로그에서 커에 대한 서명 정보를 알려면 %G? 을 이용한다.
$ git log --pretty="format:%h %G? %aN %s"
5c3386c G Scott Chacon signed commit
ca82a6d N Scott Chacon changed the version number
085bb3b N Scott Chacon removed unnecessary test code
a11bef0 N Scott Chacon first commit
위 로그에서 제일 최근 게 서명한 커이라는 것을 인할 수 있다. 다른 커들은 서명하지 않았다.
234
1.8.3 버전 이후의 Git에서는 git merge` `git pull`에서 GPG 서명 정보를 이용해 Merge 용하지
않을 있다. `--verify-signatures 옵션으로 이 기을 사용할 수 있다.
Merge 할 때 --verify-signatures 옵션이면 Merge 할 커중 서명하지 않았거나 신할 수 없는 사람이
서명한 커이 있으면 Merge 되지 않는다.
$ git merge --verify-signatures non-verify
fatal: Commit ab06180 does not have a GPG signature.
Merge 할 커전부가 신할 수 있는 사람에 의해 서명된 커이면 모든 서명을 출력하고 Merge를 수한다.
$ git merge --verify-signatures signed-branch
Commit 13ad65e has a good GPG signature by Scott Chacon (Git signing key)
<schacon@gmail.com>
Updating 5c3386c..13ad65e
Fast-forward
ÊREADME | 2 ++
Ê1 file changed, 2 insertions(+)
git merge 명령에도 -S 옵션일 수 있다. 옵션이면 Merge 을 서명하다는 의이다. 아래 예제에서
Merge 할 모든 커게 서명됐는지 인하고 Merge 에도 서명을 하는 것을 보자.
$ git merge --verify-signatures -S signed-branch
Commit 13ad65e has a good GPG signature by Scott Chacon (Git signing key)
<schacon@gmail.com>
You need a passphrase to unlock the secret key for
user: "Scott Chacon (Git signing key) <schacon@gmail.com>"
2048-bit RSA key, ID 0A46826A, created 2014-06-04
Merge made by the 'recursive' strategy.
ÊREADME | 2 ++
Ê1 file changed, 2 insertions(+)
가 서명하게 하려면
에 서명하는 것은 지지만 실제로 서명 기을 사용하려면 팀의 모든 사람이 서명 기을 이해하고
사용해만 한다. 지 않으면 팀원들에게 커을 어떻게 서명된 커으로 재생성하는지 가치느라 세
보내게 될 것이다. 드시 작에 적용하기 전에 GPG 서명 기을 이해하고 이 기이 가지는 장점전히 하고
있어만 한다.
검색
프로젝트가 크든 작든 함수의 정의나 함수가 호출되는 하는 경우가 많다. 함수의 히스토리찾아보기도
235
한다. Git은 데이터이스에 저된 코드나 커에서 원하는 부분을 빠르고 쉽게 하는 도가 여러 가지 있으며
으로 함살펴보자.
Git Grep
Gitgrep 명령을 이용하면 커의 내용이나 렉토리의 내용을 문자열이나 정규표현식을 이용해 쉽게
수 있다. Git 소스를 예로 들어 명령을 어떻게 사용하는지 알보자.
적으로 대상을 지정하지 않으면 렉토리일에서 는다. 명령을 실할 때 -n 또는 --line-number
옵션을 추가하면 을 문자열이 위치한 라인 호도 이 출력한다.
$ git grep -n gmtime_r
compat/gmtime.c:3:#undef gmtime_r
compat/gmtime.c:8: return git_gmtime_r(timep, &result);
compat/gmtime.c:11:struct tm *git_gmtime_r(const time_t *timep, struct tm
*result)
compat/gmtime.c:16: ret = gmtime_r(timep, result);
compat/mingw.c:826:struct tm *gmtime_r(const time_t *timep, struct tm
*result)
compat/mingw.h:206:struct tm *gmtime_r(const time_t *timep, struct tm
*result);
date.c:482: if (gmtime_r(&now, &now_tm))
date.c:545: if (gmtime_r(&time, tm)) {
date.c:758: /* gmtime_r() in match_digit() may have clobbered
it */
git-compat-util.h:1138:struct tm *git_gmtime_r(const time_t *, struct tm
*);
git-compat-util.h:1140:#define gmtime_r git_gmtime_r
git grep 명령에서 쓸만한 가지 옵션을 좀 더 살펴보자.
예를 들어 위의 과 대신 어떤 파일에서 개나 았는지만 알고 다면 -c 또는 --count 옵션을 이용한다.
$ git grep --count gmtime_r
compat/gmtime.c:4
compat/mingw.c:1
compat/mingw.h:1
date.c:3
git-compat-util.h:2
되는 라인이 있는 함수나 서드를 다면 -p 또는 --show-function 옵션.
236
$ git grep -p gmtime_r *.c
date.c=static int match_multi_number(timestamp_t num, char c, const char
*date,
date.c: if (gmtime_r(&now, &now_tm))
date.c=static int match_digit(const char *date, struct tm *tm, int
*offset, int *tm_gmt)
date.c: if (gmtime_r(&time, tm)) {
date.c=int parse_date_basic(const char *date, timestamp_t *timestamp, int
*offset)
date.c: /* gmtime_r() in match_digit() may have clobbered it */
gmtime_r 함수를 date.c 일에서 match_multi_number, match_digit 함수에서 호출하고 있다는 걸 인할
수 있다(번째로 호출하는 과는 주에 있는 것을 인할 수 있다).
--and 옵션을 이용해서 여러 어가 한 라인에 동시에 나타나는 줄 찾복잡합으로 할 수 있다. 예를 들어
“LINK” “BUF_MAX둘 중 하나를 포함한 상수 정의를 1.8.0 이전 버전의 Git 소스 코드에서 하는 것을 할 수 있다(
--break --heading 옵션여 더 형태라서 출력할 수도 있다).
$ git grep --break --heading \
Ê -n -e '#define' --and \( -e LINK -e BUF_MAX \) v1.8.0
v1.8.0:builtin/index-pack.c
62:#define FLAG_LINK (1u<<20)
v1.8.0:cache.h
73:#define S_IFGITLINK 0160000
74:#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
v1.8.0:environment.c
54:#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
v1.8.0:strbuf.c
326:#define STRBUF_MAXLINK (2*PATH_MAX)
v1.8.0:symlinks.c
53:#define FL_SYMLINK (1 << 2)
v1.8.0:zlib.c
30:/* #define ZLIB_BUF_MAX ((uInt)-1) */
31:#define ZLIB_BUF_MAX ((uInt) 1024 * 1024 * 1024) /* 1GB */
git grep 명령은 grep 이나 ack 은 일적인 보다 가지 좋은 이 있다. 선 매빠르. 또한,
렉토리만이 니라 Git 히스토리 내의 어한 정보라도 찾아수 있다. 위의 예제에서 이전 버전의 소스에서도 특정
어를 찾아낸 것을 볼 수 있다.
237
Git 로그 검색
떤 변수가 어디에 있는지를 찾아보는 게 니라, 히스토리에서 추가되거나 경됐는지 찾아볼 수도 있다. git
log 명령을 이용하면 Diff 내용도 하여 어에서 고자 하는 내용을 추가했는지 을 수 있다.
ZLIB_BUF_MAX 라는 상수가 가처음 나타난 때를 는 문제라면 -S 옵션(“pickaxe(곡괭)” 옵션이라 한다)
이용해 해당 문자열이 추가된 커과 없어할 수 있다.
$ git log -S ZLIB_BUF_MAX --oneline
e01503b zlib: allow feeding more than 4GB in one go
ef49a7a zlib: zlib can only process 4GB at a time
경 사을 살펴보면 ef49a7a 에서 ZLIB_BUF_MAX 상수가 처음 나오고 e01503b 에서는 경된 것을
알 수 있다.
더 세세한 을 걸어 다면 로그를 할 때 -G 옵션으로 정규표현식을 써서 하면 된다.
라인 로그 검색
친 듯이 좋은 로그 가 또 있다. 라인 히스토리 이다. git log 를 쓸 때 -L 옵션이면 어함수나
한 라인의 히스토리를 볼 수 있다.
예를 들어, zlib.c 일에 있는 git_deflate_bound 함수의 모든 경 사들을 보원한다고 생각해보자. git
log -L :git_deflate_bound:zlib.c 라고 명령 실하면 된다. 이 명령을 실하면 함수의 시작과
해서 함수에서 일어난 모든 히스토리를 함수가 처음 만들어때부터 Patch를 나열하여 보여.
238
$ git log -L :git_deflate_bound:zlib.c
commit ef49a7a0126d64359c974b4b3b71d7ad42ee3bca
Author: Junio C Hamano <gitster@pobox.com>
Date: Fri Jun 10 11:52:15 2011 -0700
Ê zlib: zlib can only process 4GB at a time
diff --git a/zlib.c b/zlib.c
--- a/zlib.c
+++ b/zlib.c
@@ -85,5 +130,5 @@
-unsigned long git_deflate_bound(z_streamp strm, unsigned long size)
+unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)
Ê{
- return deflateBound(strm, size);
+ return deflateBound(&strm->z, size);
Ê}
commit 225a6f1068f71723a910e8565db4e252b3ca21fa
Author: Junio C Hamano <gitster@pobox.com>
Date: Fri Jun 10 11:18:17 2011 -0700
Ê zlib: wrap deflateBound() too
diff --git a/zlib.c b/zlib.c
--- a/zlib.c
+++ b/zlib.c
@@ -81,0 +85,5 @@
+unsigned long git_deflate_bound(z_streamp strm, unsigned long size)
+{
+ return deflateBound(strm, size);
+}
+
Git이 함수의 처음과 을 인하지 못할 때는 정규표현식으로 인하게 할 수도 있다. git log -L '/unsigned
long git_deflate_bound/',/^}/:zlib.c 명령으로 위와 같과를 볼 수 있다. 한 라인의 히스토리
할 수도 있고 여러 라인에 걸히스토리할 수도 있다.
히스토리 단장하기
Git으로 일하다 보면 어이유로든 로히스토리를 수정해할 때가 있다. 정을 나중으로 미룰 수 있던 것은
Git장점이다. Staging Area로 커일을 고는 일을 커하는 순간으로 미룰 수 있고 Stash 명령으로 하던 일을
미룰 수 있다. 게다가 이해서 정한 내용을 수정할 수 있다. 고 수정할 수 있는 것도 우 다하다. 들의
순서도 경할 수 있고 커밋 메시지일도 경할 수 있다. 여러 개의 커을 하나로 합치거나 대로 커
하나를 여러 개로 분할 수도 있다. 니면 커제할 수도 있다. 하지만, 이 모든 것은 다른 사람과 코드를
유하기 전에 해한다.
239
이 절에서는 사람들과 코드를 유하기 전에 커히스토리를 예단장하는 방법에 대해서 명한다.
Git이 동작하는 기중 하나는 Git은 로에 모든 버전관리 데이터를 로(Clone)
고 있다는 이다. 이 때문에 자유게 히스토리로컬에서 수정해 볼 수 있는 자유도 누릴
있다. 다만 로의 버전관리 데이터 은 커이 외부로 Push가 된 후라면 이기는 판이된다.
Push된 데이터는 수정에 대해전이 난 것이다. 할 이유가 생더라도 새로 수정작
추가해지 이전 커를 수정할 수는 없다. 기에 온전하게 수정 작을 마무했다는
없이 작내용을 유하는 저소로 보내는(Push) 것은 동이다.
마지막 커밋을 수정하기
히스토리단장하는 일 중에서는 마지을 수정하는 것이 가자주 하는 일이다. 적으로 가지로 나
있는데 하나는 순히 커밋 메시지만를 수정하는 것이고 다른 하나는 나중에 수정한 일을 마지밋 안
것이다.
밋 메시지를 수정하는 방법우 간하다.
$ git commit --amend
이 명령은 자동으로 스트 편기를 실서 마지밋 메시지를 열어. 여기에 시지를 바고 편기를
으면 편기는 바뀐 시지로 마지을 수정한다.
대로 커밋 메시지가 니라 프로젝트 내용을 수정한 경우가 있다. 하고 난 후 새로 만든 일이나 수정한 일을
장 최근 을 수 있다. 적으로 방법. 일을 수정하고 git add 명령으로 Staging Area
는다. git commit --amend 명령으로 커하면 커가 수정되면서 추가로 수정사을 수
있다.
이때 SHA-1 이 바기 때문에 과거의 커경할 때 주의해한다. Rebase와 같이 이Push 한 커은 수정하면
된다.
커밋을 고치는 작업은 커밋 메시지 고치를 덩달아 이수 있음
을 고치는 것은 커밋 메시지를 고치는 것일수도 있고 또는 커밋 담고 있는 경 내용을 고치는 것
일수도 있다. 의 고치는데 있어 추가된 경 내용이 상당히 있을 경우 커밋 메시지가 실하게
고 있는지 인해 볼 요가 있다.
대로 커을 고치는 내용이 오타를 살고치거나 실수로 빠뜨린 것을 는 등 주 사소하거나 이
밋 메시지가 분히 이를 영하고 있을 수 있다. 이런 경우 다음과 --no-edit 옵션
사용하면 커밋 메시지를 수정하도록 편기가 실되지는 않는다.
$ git commit --amend --no-edit
커밋 메시지를 여개 수정하기
최근 니라 예전 커을 수정하려면 다른 도요하다. 히스토리 수정하기 위해 만들어는 없지만
rebase 명령을 이용하여 수정할 수 있다. 재 작하는 브랜치에서 각 커을 하나하나 수정하는 것이 니라 어느
240
부터 HEAD까지의 커을 한 Rebase 한다. 화형 Rebase 를 사용하면 커을 처할 때마다
. 그러면 각 커시지를 수정하거나 일을 추가하고 경하는 등의 일을 진행할 수 있다. git rebase
명령에 -i 옵션을 추가하면 대화형 모드로 Rebase 할 수 있다. 부터 HEAD까지 Rebase 할 것인지 인자로
넘기면 된다.
마지밋 메시지 세 개를 모수정하거나 그 중 개를 수정하는 시나오를 살펴보자. git rebase -i 의 인자로
하려는 마지의 부모를 `HEAD~2^``HEAD~3`로 해서 넘. 마지세 개의 커을 수정하는 것이기
때문에 `~3`이 좀 더 기하기 쉽다. 지만, 실질적으로 가키게 되는 것은 수정하려는 커의 부모인 네 번째 이전
이다.
$ git rebase -i HEAD~3
이 명령은 Rebase 하는 것이기 때문에 시지의 수정 여부에 계없이 HEAD~3..HEAD 위에 있는 모든 커
수정한다. 다시 강조하지만 이서버에 Push 한 커은 절대 고치지 말아야 한다. Push 한 커Rebase 하면
은 내용을 두 번 Push 하는 것이기 때문에 다른 개발자들이 스러할 것이다.
하면 Git은 수정하려는 커목록이 부된 스크트를 스트 편기로 열어.
pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
# Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
이 커은 모log 명령과는 정대의 순서로 나열된다. log 명령을 실하면 아래와 같과를 볼 수 있다.
241
$ git log --pretty=format:"%h %s" HEAD~3..HEAD
a5f4a0d added cat-file
310154e updated README formatting and added blame
f7f3f6d changed my name a bit
과의 을 기하자. 화형 Rebase는 스크트에 적있는 순서대로 `HEAD~3`부터 적용하기 시작하고
위에서 아래로 각각의 커을 순서대로 수정한다. 순서대로 적용하는 것이기 때문에 제일 위에 있는 것이 신이 니라
된 것이다.
특정 커에서 실추게 하려면 스크트를 수정해한다. pick 이라는 어를 'edit’로 수정하면 그 커에서
. 된 커밋 메시지를 수정하려면 아래와 같이 편한다.
edit f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
하고 편기를 하면 Git은 목록에 있는 커중에서 가된 커으로 이동하고, 아래와 같시지를
보여주고, 명령 프프트를 보여.
$ git rebase -i HEAD~3
Stopped at f7f3f6d... changed my name a bit
You can amend the commit now, with
Ê git commit --amend
Once you’re satisfied with your changes, run
Ê git rebase --continue
명령 프프트가 나타GitRebase 과정에서 재 정하는지 시지로 알려. 아래와 같은 명령을
하고
$ git commit --amend
밋 메시지를 수정하고 스트 편기를 하고 나서 아래 명령을 실한다.
$ git rebase --continue
게 나개의 커에 적용하면 이다. 다른 것도 pickedit로 수정해서 이 작몇 번이든 반복할 수 있다.
매번 Git출 때마다 커을 정정할 수 있고 할 때까지 계속 할 수 있다.
242
커밋 서 바꾸기
화형 Rebase 로 커제하거나 순서를 정할 수 있다. “added cat-file” 제하고 다른
의 순서를 경하려면 아래와 같Rebase 스크트를
pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
아래와 같이 수정한다.
pick 310154e updated README formatting and added blame
pick f7f3f6d changed my name a bit
수정한 내용을 저하고 편기를 하면 Git브랜치를 이 커의 부모로 이동시키고서 310154e f7f3f6d
순서대로 적용한다. 명령이 나고 나면 커순서가 경됐고 “added cat-file” 이 제거된 것을 인할 수 있다.
커밋 합치기
화형 Rebase 명령을 이용하여 여러 개의 커꾹꾹 러서 커하나로 만들어 버수 있다. Rebase 스크트에
자동으로 포함된 도움명이 있다.
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
“pick이나 “edit” “squash” 를 입력하면 Git은 해당 커과 바로 이전 커을 합것이고 커밋 메시지도 Merge
한다. 3개의 커을 모합치려면 스크트를 아래와 같이 수정한다.
243
pick f7f3f6d changed my name a bit
squash 310154e updated README formatting and added blame
squash a5f4a0d added cat-file
하고 나서 편기를 하면 Git3개의 커밋 메시지를 Merge 할 수 있도록 에디터를 바로 실.
# This is a combination of 3 commits.
# The first commit's message is:
changed my name a bit
# This is the 2nd commit message:
updated README formatting and added blame
# This is the 3rd commit message:
added cat-file
시지를 저하면 3개의 커이 모한 개만 는다.
커밋 분리하기
을 분한다는 것은 기존의 커을 해제하고(은 되려 놓고) Stage를 여러 개로 분하고 나서 그것을 원하는
수만큼 다시 커하는 것이다. 예로 들었던 커세 개 중에서 가운데 것을 분해보자. 이 커“updated README
formatting and added blame“updated README formatting” “added blame” 으로 분하는 것이다.
rebase -i 스크트에서 해당 커"edit"경한다.
pick f7f3f6d changed my name a bit
edit 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
하고 나서 명령 프프트로 넘어간 다음에 그 커을 해제하고 그 내용을 다시 개로 나서 커하면 된다.
하고 편기를 하면 Git은 제일 오된 커의 부모로 이동하고서 f7f3f6d 310154e 을 처하고 콘솔
프트를 보여. 여기서 커을 해제하는 git reset HEAD^ 라는 명령으로 커을 해제한다. 그러면 수정했던
일은 Unstaged 가 된다. 그다음에 일을 Stage 한 후 커하는 일을 원하는 만큼 반복하고 나서 git rebase
--continue 라는 명령을 실하면 Rebase 난다.
$ git reset HEAD^
$ git add README
$ git commit -m 'updated README formatting'
$ git add lib/simplegit.rb
$ git commit -m 'added blame'
$ git rebase --continue
244
a5f4a0d 도 처되면 히스토리아래와 같.
$ git log -4 --pretty=format:"%h %s"
1c002dd added cat-file
9b29157 added blame
35cfb2b updated README formatting
f3cc40e changed my name a bit
다시 강조하지만 Rebase 하면 목록에 있는 모든 커SHA-1 경된다. 절대로 이서버에 Push 한 커
수정하면 된다.
filter-branch
수정해하는 커무 많Rebase 스크트로 수정하기 어려으면 다른 방법을 사용하는 것이 좋다. 모든
의 이일 주소를 경하거나 어떤 파일을 제하는 경우를 살펴보자. filter-branch 라는 명령으로 수정할 수
있는데 Rebase이라면 이 명령은 포크인이라고 할 수 있다. filter-branch 시 수정하려는 커이 이
서 다른 사람과 함께 공유하는 중이라면 사용하지 말아야 한다. 하지만, 쓰면 유용하다. filter-branch
유용한 경우를 예로 들어 명하기 때문에 여기에서 대경우에 유용할지 배수 있다.
모든 커밋에서 파일을 제거하기
자기 가 생각 없이 git add . 은 명령을 실해서 룡 똥 덩를 커했거나 실수로 호가 포함된 일을
해서 이런 일을 다시 제해하는 상을 살펴보자. 이런 상은 생각보다 자주 발생한다. filter-branch
히스토리 에서 요한 것만 라내는 데 사용하는 도. filter-branch --tree-filter 라는 옵션
사용하면 히스토리에서 passwords.txt 일을 예 제거할 수 있다.
$ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD
Rewrite 6b9b3cf04e7c5686a9cb838c3f36a8cb6a0fc2bd (21/21)
Ref 'refs/heads/master' was rewritten
--tree-filter 옵션은 프로젝트를 Checkout 한 후에 각 커에 명시한 명령을 실시키고 그 과를 다시 커한다.
이 경우에는 각 스냅샷passwords.txt 일이 있으면 그 일을 제한다. 실수로 편기의 백업파일을 커했으면
git filter-branch --tree-filter 'rm -f *~' HEAD 라고 실해서 제할 수 있다.
이 명령은 모든 일과 커을 정하고 브랜치 포인터를 다시 원해. 이런 작스팅 브랜치에서 실하고 나서
master 브랜치에 적용하는 게 좋다. filter-branch 명령에 --all 옵션을 추가하면 모든 브랜치에 적용할 수 있다.
하위 디렉토리를 트 디렉토리로 만들기
다른 VCS에서 코드를 포트하면 그 VCS만을 위한 디렉토리가 있을 수 있다. SVN에서 코드를 포트하면 trunk, tags,
branch 렉토리가 포함된다. 모든 커에 대해 trunk 렉토리를 프로젝트 루트 디렉토리로 만들 때도 filter-
branch 명령이 유용하다.
245
$ git filter-branch --subdirectory-filter trunk HEAD
Rewrite 856f0bf61e41a27326cdae8f09fe708d679f596f (12/12)
Ref 'refs/heads/master' was rewritten
이제 trunk 렉토리를 루트 디렉토리로 만들었다. Git은 입력한 디렉토리와 관련이 없는 커을 자동으로 제한다.
모든 커밋의 이메일 주소를 수정하기
프로젝트를 오픈소스로 개할 때 마도 회사 이일 주소로 커된 것을 개인 이일 주소로 경해한다. 니면
git config 로 이름과 이일 주소를 정하는 것을 었을 수도 있다. 자신의 이일 주소만 경하도록 심해
한다. filter-branch 명령의 --commit-filter 옵션을 사용하여 해당 커라서 이일 주소를 수정할 수
있다.
$ git filter-branch --commit-filter '
Ê if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
Ê then
Ê GIT_AUTHOR_NAME="Scott Chacon";
Ê GIT_AUTHOR_EMAIL="schacon@example.com";
Ê git commit-tree "$@";
Ê else
Ê git commit-tree "$@";
Ê fi' HEAD
일 주소를 새 주소로 경했다. 모든 커은 부모의 SHA-1 을 가지고 있기 때문에 에 만하는 커SHA-
1만 바는 것이 니라 모든 커SHA-1 이 바뀐다.
Reset 명확히 알고 가기
Git의 다른 특한 도를 더 살펴보기 보기 전에 reset checkout 에 대해 이기를 해보자. 명령은 Git을 처음
사용하는 사람을 가갈리게 하는 부분이다. 제대로 이해하고 사용할 수 없을 것으로 보일 정도로 많은 기을 지.
이해하기 쉽게 간한 비유를 들어 명해보자.
세 개의 트리
Git을 서로 다른 세 트관리하는 컨텐관리자로 생각하면 reset checkout 을 좀 더 쉽게 이해할 수 있다.
여기서 실제로는 일의 이다. 료구조의 트니다 세 트Index는 트니지만, 이해를
쉽게 하려고 일라고 한다.
Git은 일적으로 세 가지 트관리하는 시스이다.
트리 역할
HEAD 마지냅샷, 다음 커의 부모 커
Index 다음에 커할 스냅샷
렉토리
246
HEAD
HEAD브랜치를 가키는 포인터이며, 브랜치는 브랜치에 담긴 중 가마지을 가. 지금의
HEAD가 가키는 커은 바로 다음 커의 부모가 된다. 순하게 생각하면 HEAD*브랜치 마지
냅샷*이다.
HEAD가 가키는 스냅샷을 살펴보기는 쉽다. 아래HEAD 냅샷의 디렉토리 리스팅과 각 일의 SHA-1
보여주는 예제다.
$ git cat-file -p HEAD
tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
author Scott Chacon 1301511835 -0700
committer Scott Chacon 1301511835 -0700
initial commit
$ git ls-tree -r HEAD
100644 blob a906cb2a4a904a152... README
100644 blob 8f94139338f9404f2... Rakefile
040000 tree 99f1a6d12cb4b6f19... lib
cat-file ls-tree 명령은 일상적으로는 사용하지 않는 저수명령이다. 이런 저수명령을 “plumbing”
명령이라고 한다. Git이 실제로 무일을 하는지 볼 때 유용하다.
Index
Index바로 다에 커밋할 것들이다. 에서 우는 이런 개념을 “Staging Area” 라고 배운 바 있다. “Staging
Area” 는 사용자가 git commit 명령을 실했을 때 Git이 처할 것들이 있는 이다.
Index렉토리에서 마지으로 Checkout 브랜치의 일 목록과 일 내용으로 워진. 이후
경작을 하고 경한 내용으로 Index데이트 할 수 있다. 데이트 하고 git commit 명령을 실하면
Index는 새 커으로 환된다.
$ git ls-files -s
100644 a906cb2a4a904a152e80877d4088654daad0c859 0 README
100644 8f94139338f9404f26296befa88755fc2598c289 0 Rakefile
100644 47c6340d6459e05787f644c2447d2595f5d3a54b 0 lib/simplegit.rb
또 다른 저수git ls-files 명령은 훨씬 장막 에 가려있는 명령으로 이를 실하면 Index가 어
인지를 인할 수 있다.
Index해 트리구조니다. 사실 Index평평구조구현되어 있다. 여기에서는 쉽게 이해할 수 있도록
라고 명한다.
247
디렉토리
마지으로 렉토리를 살펴보자. 위의 일과 그 내용을 효율적인 형태.git 렉토리에 저한다.
하지만, 사람이 알보기 어렵다. 렉토리는 실제 일로 존재한다. 바로 에 보이기 때문에 사용자가 편하기
하다. 렉토리로 생각하자. 하기 전에는 Index(Staging Area)려놓고 마든지 경할 수
있다.
$ tree
.
├── README
├── Rakefile
└── lib
Ê └── simplegit.rb
1 directory, 3 files
워크플로
Git의 주목적은 프로젝트의 스냅샷을 지속적으로 저하는 것이다. 이 트세 개를 사용해 더 나은 상관리한다.
이 과정을 시각해보자. 일이 하나 있는 디렉토리로 이동한다. 이걸 일의 v1이라고 하고 파란색으로 시한다. git
init 명령을 실하면 Git 소가 생기고 HEAD아직 없는 브랜치를 가(master 아직 없다).
248
이 시에서는 렉토리 에만 데이터가 있다.
이제 일을 커해보자. git add 명령으로 렉토리의 내용을 Index사한다.
249
git commit 명령을 실한다. 그러면 Index의 내용을 스냅샷으로 영히 저하고 그 스냅샷을 가키는 커
객체를 만든다. 고는 master 가 그 커밋 객체를 가키도록 한다.
250
이때 git status 명령을 실하면 무런 경 사이 없다고 나온다. 세 트기 때문이다.
다시 일 내용을 바고 커해보자. 위에서 했던 것과 과정은 비하다. 렉토리일을 고. 이를 이
일의 v2라고 하자. 건 빨으로 시한다.
251
git status 명령을 바로 실하면 “Changes not staged for commit,아래으로 된 일을 볼 수 있다.
Index와 워렉토리가 다른 내용을 고 있기 때문에 그. git add 명령을 실해서 경 사Index
려주자.
252
이 시에서 git status 명령을 실하면 “Changes to be committed” 아래일 이름이 으로 한다.
IndexHEAD의 다른 일들이 여기에 시된다. 다음 커할 것과 지금 마지이 다다는 이다. 마지으로
git commit 명령을 실해 커한다.
253
이제 git status 명령을 실하면 무것도 출력하지 않는다. 세 개의 트의 내용이 다시 같아기 때문이다.
브랜치를 바거나 Clone 명령도 내부에서는 비한 절는다. 브랜치를 Checkout 하면, HEAD가 새로운
브랜치를 가키도록 바, 새로운 커의 스냅샷Index에 놓는다. Index의 내용을 디렉토리
사한다.
Reset 의 역할
위의 트세 개를 이해하면 reset 명령이 어떻게 동작하는지 쉽게 알 수 있다.
예로 들어 file.txt 일 하나를 수정하고 커한다. 이것을 세 번 반복한다. 그러면 히스토리아래와 같이 된다.
254
자 이제 reset 명령이 정히 어일을 하는지 낱낱보자. reset 명령은 이 세 트를 간하고 예
방법으로 작한다. 작하는 동작은 세 계 이하로 이루어.
1 단계: HEAD 이동
reset 명령이 하는 번째 일은 HEAD 브랜치를 이동시. checkout 명령처럼 HEAD가 가키는 브랜치를
지는 않는다. HEAD는 계속 브랜치를 가키고 있고, 브랜치가 가키는 커을 바. HEADmaster
브랜치를 가키고 있다면(master 브랜치를 Checkout 하고 작하고 있다면) git reset 9e5e6a4 명령은
master 브랜치가 `9e5e6a4`를 가키게 한다.
255
reset 명령에 커을 넘기고 실하면 제나 이런 작을 수한다. reset --soft 옵션을 사용하면 여기까지
진행하고 동작을 .
이제 위의 다이어그을 보고 어일이 일어난 것인지 생각해보자. reset 명령은 가장 최근git commit 명령을
돌린. git commit 명령을 실하면 Git은 새로운 커을 생성하고 HEAD가 가키는 브랜치가 새로운 커
키도록 데이트한다. reset 명령 HEAD~ (HEAD의 부모 커)를 주면 Index렉토리는 그대로
브랜치가 가키는 커만 이전으로 되돌린. Index데이트한 다음에 git commit 명령를 실하면 git
commit --amend 명령의 와 같아진(마지을 수정하기를 참).
2 단계: Index 업데이트 (--mixed)
여기서 git status 명령을 실하면 Indexreset 명령으로 이동시HEAD의 다른 으로 출력된다.
reset 명령은 여기서 한 발더 나IndexHEAD가 가키는 스냅샷으로 데이트할 수 있다.
256
--mixed 옵션을 주고 실하면 reset 명령은 여기까지 하고 . reset 명령을 실할 때 옵션도 주지 않으면
적으로 --mixed 옵션으로 동작한다(예제와 같git reset HEAD~ 처럼 명령을 실하는 경우).
위의 다이어그을 보고 어일이 일어지 한 더 생각해보자. 키는 대상을 가장 최근 으로 되돌리는 것은
. 그러고 나서 Staging Area 를 비우기까지 한다. git commit 명령도 되돌리git add 명령까지 되돌리
것이다.
3 단계: 디렉토리 업데이트 (--hard)
reset 명령은 세 번째렉토리까지 데이트한다. --hard 옵션을 사용하면 reset 명령은 이 계까지
한다.
257
이 과정은 어떻게 동작하는지 가해보자. reset 명령을 git add git commit 명령으로 생성한 마지
을 되돌린. 그리고 렉토리의 내용까지도 되돌린.
--hard 옵션우 중요하다. reset 명령을 위하게 만드는 유일한 옵션이다. Git에는 데이터를 실제로
제하는 방법로 없다. 제하는 방법은 그 중 하나다. reset 명령을 어떻게 사용하더라도 간과를 되돌릴
수 있다. 하지만 --hard 옵션은 되돌리는 것이 하다. 옵션을 사용하면 렉토리일까지 제로
. 이 예제는 일의 v3버전을 아직 Git이 커으로 보하고 있기 때문에 reflog 를 이용해서 다시 원할 수
있다. 한 적 없다면 Git데이터는 원할 수 없다.
복습
reset 명령은 정해순서대로 세 개의 트어써 나가다가 옵션에 따라 지정한 에서 .
1. HEAD가 가키는 브랜치를 . (--soft 옵션이 으면 여기)
2. IndexHEAD가 가키는 상로 만든다. (--hard 옵션이 지 않으면 여기)
258
3. 렉토리Index의 상로 만든다.
경로를 주고 Reset 하기
지금까지 reset 명령을 실하는 기본 형태와 사용 방법을 살펴. reset 명령을 실할 때 경로를 지정하면 1계를
고 정해경로의 일에만 나reset 계를 적용한다. 이는 당한 이기다. HEAD는 포인터인데 경로에
따라 로 기이 되는 커을 부분적으로 적용하는 하다. 하지만, Index렉토리는 일부분만
신할 수 있다. 따라서 2, 3계는 가하다.
예를 들어 git reset file.txt 명령을 실한다고 가정하자. 형식(의 해시 이나 브랜치도 기하지 않고
--soft --hard 기하지 않은) git reset --mixed HEAD file.txt 것이다.
1. HEAD브랜치를 . (건너뜀)
2. IndexHEAD가 가키는 상로 만든다. (여기서 멈춤)
질적으로는 file.txt 일을 HEAD에서 Index사하는 것뿐이다.
259
이 명령은 해당 일을 Unstaged 로 만든다. 이 명령의 다이어그git add 명령을 비해보면 정대인
것을 알 수 있다.
이것이 git status 명령에서 이 명령을 보여주는 이유다. 이 명령으로 일을 Unstaged 로 만들 수 있다. (더 자세한
내용은 일 상Unstage경하기를 참고한다.)
특정 커을 명시하면 GitHEAD에서 일을 오는것이 니라 에서 일을 온다. `git
reset eb43bf file.txt 명령과 이 실한다.
260
이 명령을 실한 것과 과를 만들려면 렉토리일을 v1으로 되돌리git add 명령으로 Index
v1으로 만들고 나서 다시 렉토리v3로 되한다(과만 다는 기다). 이 상에서 git commit
명령을 실하면 v1으로 되돌린 파일 내용을 기록한다. 렉토리를 사용하지 않았다.
git add 명령처럼 reset 명령도 Hunk 위로 사용할 수 있다. --patch 옵션을 사용해서 Staging Area에서 Hunk
위로 Unstaged 로 만들 수 있다. 선택적으로 Unstaged 로 만들거나 내거나 이전 버전으로 원시
수 있다.
합치기(Squash)
여러 커을 커하나로 합치는 재는 도를 알보자.
“oops.“WIP”, “forgot this file” 깃털이 가운 커들이 있다고 해보자. 때는 reset 명령으로
들을 하나로 합들에게 똑똑한 척할 수 있다. (합치기를 하는 명령어가 따로 있지만, 여기서는 reset
명령을 쓰는 것이 더 간할 때도 있다는 것을 보여.)
이런 프로젝트가 있다고 생각해보자. 번째 일 하나를 추가했고, 두 번째 은 기존 일을 수정하고 새로운
261
일도 추가했다. 번째 번째 파일을 다시 수정했다. 두 번째 아직 중인 커으로 이 커을 세
번째 과 합치고 은 상이다.
git reset --soft HEAD~2 명령을 실하여 HEAD 포인터를 이전 커으로 되돌릴 수 있다(히스토리에서 그대로
유지할 처음 커밋 말이다).
262
이 상에서 git commit 명령을 실한다.
263
이제 사람들에게 개할만한 히스토리가 만들어. file-a.txt 일이 있는 v1 이 하나 그대로 있고, 두 번째
에는 v3버전의 file-a.txt 일과 새로 추가된 file-b.txt 일이 있다. v2 버전은 더는 히스토리에 없다.
Checkout
마도 checkout 명령과 reset 명령에 어떤 차이가 있는지 금할 것이다. reset 명령과 마가지로 checkout
명령도 위의 세 트작한다. checkout 명령도 일 경로를 쓰느쓰느에 따라 동작이 다.
264
경로 없음
git checkout [branch] 명령은 git reset --hard [branch] 명령과 비하게 [branch] 냅샷
으로 세 트작한다. 하지만, 가지 사이 다.
번째reset --hard 명령과는 달checkout 명령은 렉토리전하게 다. 하지 않은 것이
있는지 인해서 려버지 않는다는 것을 보한다. 사실 보기보다 좀 더 똑똑하게 동작한다. 렉토리에서 Merge
을 한시도해보고 경하지 않은 일만 데이트한다. reset --hard 명령은 인하지 않고 순히 모든
것을 바.
두 번째 중요한 은 어떻게 checkout 명령이 HEAD데이트 하는가이다. reset 명령은 HEAD가 가키는
브랜치를 움이지만(브랜Refs데이트하지만), checkout 명령은 HEAD 를 다른 브랜치로 .
예를 들어 각각 다른 커을 가키는 master develop 브랜치가 있고 렉토리develop 브랜치라고
가정해보자(HEADdevelop 브랜치를 가). git reset master 명령을 실하면 develop 브랜치는
master 브랜치가 가키는 커은 커을 가키게 된다. git checkout master 명령을 실하면
develop 브랜치가 가키는 커은 바지 않고 HEADmaster 브랜치를 가키도록 데이트된다. 이제 HEAD
master 브랜치를 가키게 된다.
서 위 경우 모HEAD과적으로 A 을 가키게 되지만 방식전히 다. reset 명령은 HEAD
키는 브랜치의 포인터를 옮겼checkout 명령은 HEAD 옮겼.
265
경로 있음
checkout 명령을 실할 때 일 경로를 수도 있다. reset 명령과 비하게 HEAD는 움이지 않는다. 동작은 git
reset [branch] file 명령과 비하다. Index의 내용이 해당 커버전으로 경될 뿐만 니라 렉토리
일도 해당 커버전으로 경된다. 전히 git reset --hard [branch] file 명령의 동작이랑 같.
렉토리전하지도 않고 HEAD도 움이지 않는다.
git reset 이나 git add 명령처럼 checkout 명령도 --patch 옵션을 사용해서 Hunk 위로 되돌릴 수 있다.
요약
reset 명령이 좀 더 을 거라고 생각한다. 아직 checkout 명령과 정하게 무엇이 다른지 거나 정
사용을 다 히지 못했을 수도 있지만 괜찮.
아래에 어명령이 어에 영을 주는지에 대한 요약표비했다. 명령이 HEAD가 가키는 브랜치를
인다면 “HEAD” 열에 “REF” 라고 적있고 HEAD 가 움인다면 “HEAD” 라고 적있다. 'WD Safe?' 열을
보자. 여기에 *NO*라고 적있다면 렉토리에 저하지 않은 내용이 전하지 않기 때문에 해당 명령을 실하기
전에 한 번쯤 더 생각해보아야 한다.
HEAD Index Workdir WD Safe?
Commit Level
reset --soft [commit]
REF NO NO YES
reset [commit]
REF YES NO YES
reset --hard [commit]
REF YES YES NO
checkout <commit>
HEAD YES YES YES
File Level
reset [commit] <paths>
NO YES NO YES
checkout [commit] <paths>
NO YES YES NO
Merge
GitMerge. Git에서는 브랜리 몇 번이고 Merge 하기가 쉽다. 오랫동합치지 않은 두 브랜치를 한
Merge 하면 거대한 이 발생한다. 그마한 을 자주 고 그걸 어나으로써 브랜치를 신으로 유지한다.
하지만, 까다로운 도 발생한다. 다른 버전 관리 시스과 달Git이 나면 모호한 상까지 해하려 들지
않는다. GitMerge될지 지 판하는 것을 하자이다. 이 나도 자동으로 해하려고 노력하지
않는다. 오랫동따로 유지한 두 브랜치를 Merge 하려면 가지 해할 일이 있다.
이 절에서는 어Git 명령을 사용해서 무일을 해하는지 알보자. 그 외에도 특수한 상에서 사용하는 Merge
방법Merge마무하는 방법을 소개한다.
Merge 충돌
의 기에서 기적인 Merge 에 대해서 다. Git복잡Merge 을 때 요한 도도 가지고
있다. 일이 일어고 어떻게 해하는 게 나은지 알 수 있다.
266
Merge 할 때는 수 있어서 Merge 하기 전에 렉토리깔끔히 정하는 것이 좋다. 렉토리
하던 게 있다면 브랜치에 커하거나 Stash . 래야 일이 일어나도 다시 되돌릴 수 있다. 중인
일을 저하지 않은 Merge 하면 작했던 일부를 을 수도 있다.
우 간한 예제를 따라가 보자. 'hello world’를 출력하는 Ruby 일을 하나 가지고 있다.
#! /usr/bin/env ruby
def hello
Ê puts 'hello world'
end
hello()
소에 whitespace 브랜치를 생성하고 모든 Unix DOS 으로 바어 커한다. 일의 모든 라인이
었지만, 백만 바었다. 그 후 “hello world” 문자열을 “hello mundo로 바다음에 커한다.
$ git checkout -b whitespace
Switched to a new branch 'whitespace'
$ unix2dos hello.rb
unix2dos: converting file hello.rb to DOS format ...
$ git commit -am 'converted hello.rb to DOS'
[whitespace 3270f76] converted hello.rb to DOS
Ê1 file changed, 7 insertions(+), 7 deletions(-)
$ vim hello.rb
$ git diff -b
diff --git a/hello.rb b/hello.rb
index ac51efd..e85207e 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,7 +1,7 @@
Ê#! /usr/bin/env ruby
Êdef hello
- puts 'hello world'
+ puts 'hello mundo'^M
Êend
Êhello()
$ git commit -am 'hello mundo change'
[whitespace 6d338d2] hello mundo change
Ê1 file changed, 1 insertion(+), 1 deletion(-)
master 브랜치로 다시 이동한 다음에 함수에 대한 명을 추가한다.
267
$ git checkout master
Switched to branch 'master'
$ vim hello.rb
$ git diff
diff --git a/hello.rb b/hello.rb
index ac51efd..36c06c8 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,5 +1,6 @@
Ê#! /usr/bin/env ruby
+# prints out a greeting
Êdef hello
Ê puts 'hello world'
Êend
$ git commit -am 'document the function'
[master bec6336] document the function
Ê1 file changed, 1 insertion(+)
이때 whitespace 브랜치를 Merge 하면 이 난다.
$ git merge whitespace
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Automatic merge failed; fix conflicts and then commit the result.
Merge 소하기
Merge 중에 발생한 을 해하는 방법가지가 있다. 번째는 그저 이 상어나는 것이다. 예상하고 있던
일도 니고 지금 당할 일도 니라면 git merge --abort 명령으로 간Merge 하기 전으로 되돌린.
$ git status -sb
## master
UU hello.rb
$ git merge --abort
$ git status -sb
## master
git merge --abort 명령은 Merge 하기 전으로 되돌린. 전히 로 되돌리지 못하는 유일한 경우는 Merge 전에
렉토리에서 Stash 하지 않았거나 커하지 않은 일이 존재하고 있었을 때뿐이다. 그 외에는 잘 돌아간다.
268
이유로든 Merge를 처음부터 다시 하고 다면 git reset --hard HEAD 명령으로 되돌릴 수 있다. 이 명령은
렉토리를 그 시으로 전히 되려서 저하지 않은 것은 사라다는 에 주의하자.
무시하기
백 때문에 때도 있다. 순한 상이고 실제로 일을 살펴을 때 한 의 모든 라인이 지지고 다른
에는 추가됐기 때문에 간하다고 할 수 있다. 적으로 Git은 이런 모든 라인이 경됐다고 인지하여 Merge 할 수
없다.
Merge 백의 변화는 무시하도록 하는 옵션을 주는 것이다. Merge 할 때 무수한 백 때문에 문제가 생기면
Merge소한 다음 -Xignore-all-space -Xignore-space-change 옵션을 주어 다시 Merge 한다.
번째 옵션모든 백을 무시하고 두 번째 옵션있는 백을 하나로 한다.
$ git merge -Xignore-space-change whitespace
Auto-merging hello.rb
Merge made by the 'recursive' strategy.
Êhello.rb | 2 +-
Ê1 file changed, 1 insertion(+), 1 deletion(-)
위 예제는 모든 경 사을 무시하면 실제 일은 나지 않고 모든 Merge된다.
팀원 중 가 스이스를 으로 바거나 을 스이스로 바을 했을 때 이 옵션이 그대를 원해 .
수동으로 Merge 하기
Merge 할 때 백 처옵션을 사용하면 Git. 하지만, Git이 자동으로 해하지 못하는 때도 있다.
때는 외부 도의 도움을 받아 한다. 예를 들어 Git이 자동으로 해해주지 못하는 상에 부치면 으로
한다.
일을 dos2unix 환하고 Merge 하면 된다. 이걸 Git에서 어떻게 하는지 살펴보자.
Merge 에 있다고 치자. 일과 Merge , 공통 조상의 일이 요하다. 일들로
Merge 되도록 수정하고 다시 Merge를 시도해한다.
세 가지 버전의 일을 쉽다. Git은 세 버전의 모든 일에 “stages” 자를 여서 Index에 다 가지고 있다.
Stage 1공통 조, Stage 2재 개발자의 버전에 해당하는 , Stage 3MERGE_HEAD 가 가키는
일이다.
git show 명령으로 각 버전의 일을 수 있다.
$ git show :1:hello.rb > hello.common.rb
$ git show :2:hello.rb > hello.ours.rb
$ git show :3:hello.rb > hello.theirs.rb
좀 더 저수으로 고들자면 ls-files -u 명령을 사용한다. 이 명령은 Plumbing 명령으로 각 일을 나타내는 Git
BlobSHA-1을 수 있다.
269
$ git ls-files -u
100755 ac51efdc3df4f4fd328d1a02ad05331d8e2c9111 1 hello.rb
100755 36c06c8752c78d2aff89571132f3bf7841a7b5c3 2 hello.rb
100755 e85207e04dfdd5eb0a1e9febbc67fd837c44a1cd 3 hello.rb
:1:hello.rb 는 그Blob SHA-1를 지하는 줄임말이다.
이제 렉토리에 세 버전의 일을 모왔다. 백 문제를 수동으로 고다음에 다시 Merge 한다. Merge
때는 'git merge-file' 명령을 이용한다.
$ dos2unix hello.theirs.rb
dos2unix: converting file hello.theirs.rb to Unix format ...
$ git merge-file -p \
Ê hello.ours.rb hello.common.rb hello.theirs.rb > hello.rb
$ git diff -b
diff --cc hello.rb
index 36c06c8,e85207e..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,8 -1,7 +1,8 @@@
Ê #! /usr/bin/env ruby
Ê+# prints out a greeting
Ê def hello
- puts 'hello world'
+ puts 'hello mundo'
Ê end
Ê hello()
게 해서 지게 Merge일을 었다. 사실 이것이 ignore-all-space 옵션을 사용하는 것보다 더 나은
방법이다. 백을 무시하지 않고 실제로 고기 때문이다. ignore-all-space 옵션을 사용한 Merge 에서는
여전히 DOS의 개문자가 남아서 한 일에 두 형식의 개문자가 뒤섞인다.
Merge 하기 전에 부모에 대해서 무엇이 바었는지 인하려면 git diff 를 사용한다. 이 명령을
이용하면 Merge 과로 렉토리에 무엇이 바었는지 알 수 있다. 자세히 살펴보자.
Merge 후의 과를 Merge 하기 전의 브랜하려면, 다시 해 무엇이 합쳐졌는지 알려면 git diff --ours
명령을 실한다.
270
$ git diff --ours
* Unmerged path hello.rb
diff --git a/hello.rb b/hello.rb
index 36c06c8..44d0a25 100755
--- a/hello.rb
+++ b/hello.rb
@@ -2,7 +2,7 @@
Ê# prints out a greeting
Êdef hello
- puts 'hello world'
+ puts 'hello mundo'
Êend
Êhello()
위의 과에서 Merge를 했을 때 브랜치에서는 무엇을 추가했는지를 알 수 있다.
Merge 일을 가과 비해서 무엇이 바었는지 보려면 git diff --theirs 를 실한다. 아래
예제에서는 백을 빼고 비하기 위해 -b 옵션이 써주었다.
$ git diff --theirs -b
* Unmerged path hello.rb
diff --git a/hello.rb b/hello.rb
index e85207e..44d0a25 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,5 +1,6 @@
Ê#! /usr/bin/env ruby
+# prints out a greeting
Êdef hello
Ê puts 'hello mundo'
Êend
마지으로 git diff --base 를 사용해서 두와 하여 바뀐 을 알아본.
271
$ git diff --base -b
* Unmerged path hello.rb
diff --git a/hello.rb b/hello.rb
index ac51efd..44d0a25 100755
--- a/hello.rb
+++ b/hello.rb
@@ -1,7 +1,8 @@
Ê#! /usr/bin/env ruby
+# prints out a greeting
Êdef hello
- puts 'hello world'
+ puts 'hello mundo'
Êend
Êhello()
수동 Merge를 위해서 만들었던 각일은 이제 요 없으니 git clean 명령을 실해서 지워준.
$ git clean -f
Removing hello.common.rb
Removing hello.ours.rb
Removing hello.theirs.rb
충돌 파일 Checkout
서 살펴여러가지 방법으로 을 해했지만 바라던 과가 수도 있고 심지어 과가 동작하지 않
접 수동으로 더 많은 정보를 살펴보며 해하는 경우도 있다.
예제를 금 바보자. 예제에서는 브랜개가 있다. 브랜치에는 개의 커이 있는데
Merge 할 때 드시 만한 내용이 들어 있다.
$ git log --graph --oneline --decorate --all
* f1270f7 (HEAD, master) update README
* 9af9d3b add a README
* 694971d update phrase to hola world
| * e3eb223 (mundo) add more tests
| * 7cff591 add testing script
| * c3ffff1 changed text to hello mundo
|/
* b7dcc89 initial hello world code
master 에만 있는 세 개의 커mundo 브랜치에만 존재하는 또 다른 세 개의 커이 있다. master 브랜치에서
mundo 브랜치를 Merge 하면 이 난다.
272
$ git merge mundo
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Automatic merge failed; fix conflicts and then commit the result.
해당 일을 열어서 이 발생한 내용을 보면 아래와 같.
#! /usr/bin/env ruby
def hello
<<<<<<< HEAD
Ê puts 'hola world'
=======
Ê puts 'hello mundo'
>>>>>>> mundo
end
hello()
브랜치에서 추가된 부분이 이 일에 다 적용됐다. 적용한 커일의 은 부분을 수정해서 위와 같
.
을 해하는 가지 도에 대해 알보자. 면 이 을 어떻게 해하는지 명하지 않을 수도 있다.
을 좀 더 살펴하는 상이다.
git checkout 명령에 --conflict 옵션여 사용하는 게 좋은 방법이 될 수 있다. 이 명령은 일을 다시
Checkout 받아돌 표시된 부분을 교체한다. 난 부분은 원의 코드로 되돌리고 다시 고보려고 할 때 알
.
--conflict 옵션에는 diff3` `merge 를 넘수 있고 merge 가 기이다. --conflict 옵션diff3
사용하면 Git간 다른 모돌 표시를 남긴. “ours” “theirs고도 “base버전의 내용까지 제한다.
$ git checkout --conflict=diff3 hello.rb
위 명령을 실하면 아래와 같과가 나타난다.
273
#! /usr/bin/env ruby
def hello
<<<<<<< ours
Ê puts 'hola world'
||||||| base
Ê puts 'hello world'
=======
Ê puts 'hello mundo'
>>>>>>> theirs
end
hello()
이런 형태돌 표시를 계속 보고 다면 기으로 사용하도록 merge.conflictstyle diff3
정한다.
$ git config --global merge.conflictstyle diff3
git checkout 명령도 --ours --theirs 옵션을 지원한다. 옵션Merge 하지 않고 둘 중 한만을 선택할 때
사용한다.
옵션은 바이너리 파일이 나서 한선택하는 상이나 한브랜치의 온전한 일을 원할 때 사용할 수
있다. Merge 하고 나서 특정 일만 Checkout 한 후에 커하는 방법도 있다.
Merge 로그
git log 명령은 을 해할 때도 도움이 된다. 로그에는 을 해할 때 도움이 될만한 정보가 있을 수 있다. 과거를
보면 개발 당시에 을 고만 했던 이유를 밝혀내는 데 도움이 된다.
“Triple Dot” 을 이용하면 Merge 에 사용한 양 브랜치의 모든 커의 목록을 을 수 있다. 자세한 문Triple
Dot를 참고한다.
$ git log --oneline --left-right HEAD...MERGE_HEAD
< f1270f7 update README
< 9af9d3b add a README
< 694971d update phrase to hola world
> e3eb223 add more tests
> 7cff591 add testing script
> c3ffff1 changed text to hello mundo
와 같6개의 커을 볼 수 있다. 이 어떤 브랜치에서 온 것인지 보여.
에 따라 요한 과만 추려 볼 수도 있다. git log 명령에 --merge 옵션을 추가하면 이 발생한 일이 속한
만 보여.
274
$ git log --oneline --left-right --merge
< 694971d update phrase to hola world
> c3ffff1 changed text to hello mundo
--merge 대신 -p 를 사용하면 일의 경사만 볼 수 있다. 는지 또 이를 해하기 위해
어떻게 해하는지 이해하는 데 유용하다.
Combined Diff
Merge가 성적으로 일은 Staging Area려놓았다. 이 상에서 일들이 그대로 있을 때 git diff
명령을 실하면 일이 무엇인지 알 수 있다. 걸 더 고하는지 는 데에 도움이 된다.
Merge 하다가 을 때 git diff 명령을 실하면 생소한 Diff 과를 보여.
$ git diff
diff --cc hello.rb
index 0399cd5,59727f0..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,11 @@@
Ê #! /usr/bin/env ruby
Ê def hello
++<<<<<<< HEAD
Ê+ puts 'hola world'
++=======
+ puts 'hello mundo'
++>>>>>>> mundo
Ê end
Ê hello()
이런 형식“Combined Diff라고 한다. 각 라인은 개의 럼으로 분할 수 있다. 번째 컬럼은 “ours” 브랜
렉토리(추가 또는 )를 보여. 두 번째 컬럼은 “theirs” 와 워렉토리사이의 이를 나타.
이 예제에서 <<<<<<< >>>>>>> 마커 시는 어에도 존재하지 않고 추가된 코드라는 것을 알 수 있다.
시는 Merge 가 만들어코드이기 때문이다. 물론 시는 지워야 하는 라인이다.
을 다 해하고 git diff 명령을 다시 실하면 아래와 같이 보여. 과도 유용하다.
275
$ vim hello.rb
$ git diff
diff --cc hello.rb
index 0399cd5,59727f0..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
Ê #! /usr/bin/env ruby
Ê def hello
- puts 'hola world'
Ê- puts 'hello mundo'
++ puts 'hola mundo'
Ê end
Ê hello()
과는 세 가지 사실을 보여. “hola world” Our 브랜치에 있었지만 렉토리에는 없다. “hello mundo
Their 브랜치에 있었지만 렉토리에는 없다. “hola mundo는 어느 브랜치에도 없고 렉토리에는
있다. 을 해하고 마지으로 인하고 나서 커하는 데 유용하다.
이 정보를 git log 명령을 해서도 을 수 있다. Merge 후에 무엇이 어떻게 바었는지 알아야 할 때 유용하다.
Merge 에 대해서 git show 명령을 실하거나 git log -p --cc 옵션을 추가해도 과를 을 수
있다. git log -p 명령은 기적으로 Merge Patch를 출력한다.
276
$ git log --cc -p -1
commit 14f41939956d80b9e17bb8721354c33f8d5b5a79
Merge: f1270f7 e3eb223
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Sep 19 18:14:49 2014 +0200
Ê Merge branch 'mundo'
Ê Conflicts:
Ê hello.rb
diff --cc hello.rb
index 0399cd5,59727f0..e1d0799
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
Ê #! /usr/bin/env ruby
Ê def hello
- puts 'hola world'
Ê- puts 'hello mundo'
++ puts 'hola mundo'
Ê end
Ê hello()
Merge 되돌리기
지금까지 Merge 하는 방법을 배으나 Merge 할 때 실수할 수도 있다. Git에서는 실수해도 된다. 실수해도 (대부분
하게) 돌릴 수 있다.
Merge 도 예외는 니다. 토픽 브랜치에서 일을 하다가 master Merge 했다고 생각해보자. 히스토리
아래와 같.
277
그림 138. 발적인 Merge 커밋.
근 방식은 원하는 과에 따라 가지로 나수 있다.
Refs 수정
실수로 생Merge 이 로소에만 있을 때는 브랜치를 원하는 커을 가키도록 기는 것이 쉽고 빠르.
Merge 하고 나서 git reset --hard HEAD~ 명령으로 브랜치를 되돌리면 된다.
그림 139. git reset --hard HEAD~ 실행 후의 히스토리.
reset 에 대해서는 이Reset 히 알고 가기에서 다었기 때문에 이 내용이 그어렵않을 것이다.
하게 습해보자. reset --hard 명령은 아래의 세 계로 수한다.
1. HEAD브랜치를 지정한 위치로 . 이 경우master 브랜치를 Merge (C6) 이전으로 되돌린.
278
2. IndexHEAD의 내용으로 바.
3. 렉토리Index의 내용으로 바.
방법단점은 히스토리를 다시 다는 것이다. 다른 사람들과 유된 저소에서 히스토리어쓰면 문제가 생
있다. 문제가 일어나는지 알고 다면 Rebase 의 위를 참고하자. 해 다시 쓰는 커이 이다른
사람들과 유한 커이라면 reset 하지 않는 게 좋다. 방법Merge 하고 나서 다른 커을 생성했다면 제대로
동작하지 않는다. HEAD를 이동시키면 Merge 이후에 만든 커어버.
커밋 되돌리기
브랜치를 기는 것을 할 수 없는 경우는 모든 경사소하는 새로운 커을 만들 수도 있다. Git에서 이 기
“revert” 라고 부른다. 지금의 경우아래처럼 실한다.
$ git revert -m 1 HEAD
[master b1d8379] Revert "Merge branch 'topic'"
-m 1 옵션은 부모가 보호되어하는 “mainline” 이라는 것을 나타. HEAD Merge를 했을 때(git merge
topic1) Merge 개의 부모 커을 가. 번째 부모 커HEAD (C6)이고 두 번째 부모 커Merge
대상 브랜(C4)이다. 두 번째 부모 커(C4)에서 받아온 모든 경사을 되돌리번째 부모(C6)로부터 받아
경사고자 하는 상이다.
경사을 되돌린 은 히스토리에서 아래와 같이 보인다.
그림 140. git revert -m 1 실행 후의 히스토리
새로 만든 커^M C6 과 내용이 전히 똑같. Merge 한 커까지 HEAD 의 히스토리에서 볼 수 있다는 것
고는 Merge 하지 않은 것과 . topic 브랜치를 master 브랜치에 다시 Merge 하면 Git아래와 같
절해한다.
$ git merge topic
Already up-to-date.
279
Merge 했던 topic 브랜치에는 더는 master 브랜치로 Merge 할 내용이 없다. 을 더 게 하는 경우는
topic 에서 가 더 일을 하고 다시 Merge를 하는 경우이다. GitMerge 이후에 새로 만들어만 가온다.
그림 141. 지 않은 Merge가 있는 히스토리
이러면 가좋은 방법은 되렸던 Merge 을 다시 되돌리는 것이다. 이후에 추가한 내용을 새 Merge 으로
만드는 게 좋다.
$ git revert ^M
[master 09f0126] Revert "Revert "Merge branch 'topic'""
$ git merge topic
그림 142. 되돌린 Merge를 다시 Merge 한 후의 히스토리
위 예제에서는 M ^M 이 상됐다. ^^M C3 C4 경 사고 있고 C8 C7 의 내용을 훌륭하게 Merge
했다. 하여 topic 브랜치를 전히 Merge 한 상가 됐다.
다른 방식의 Merge
지금까지 두 브랜치를 하게 Merge 하는 방법에 대해 알보았다. Merge는 보“recursive을 사용한다.
브랜치를 한 Merge 하는 방법은 여러 가지다. 그 중 개만 간히 알보자.
Our/Their 선택하기
저 일적인 “recursive을 사용하는 Merge 을 할 때 유용한 옵션을 소개한다. 에서 ignore-all-
280
space ignore-space-change -X 옵션여 쓰는 것을 보았다. -X 옵션을 때 어
선택할 때도 사용한다.
옵션도 지정하지 않고 두 브랜치를 Merge 하면 Git은 코드에 시하고 해당 일을 일로
시해. 접 해하는 게 니라 미리 Git에게 을 때 두 브랜치 중 한선택하라고 알려
있다. merge 명령을 사용할 때 -Xours Xtheirs 옵션을 추가하면 된다.
Git에 이 옵션을 주면 돌 표시가 지 않는다. Merge가 가하면 Merge 될 것이고 이 나면 사용자가 명시한
내용으로 대한다. 바이너리 파일도 똑같.
“hello world” 예제로 돌아가서 다시 Merge를 해보자. Merge를 하면 이 나는 것을 볼 수 있다.
$ git merge mundo
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Resolved 'hello.rb' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.
하지만 -Xours -Xtheirs 옵션을 주면 다는 소가 없다.
$ git merge -Xours mundo
Auto-merging hello.rb
Merge made by the 'recursive' strategy.
Êhello.rb | 2 +-
Êtest.sh | 2 ++
Ê2 files changed, 3 insertions(+), 1 deletion(-)
Êcreate mode 100644 test.sh
일에는 “hello mundo가 있고 다른 일에는 “hola world” 가 있다. Merge에서 돌 표시를 하는 대신
“hola world” 선택한다. 나지 않은 나지는 Merge 된다.
옵션git merge-file 명령에도 사용할 수 있다. 에서 이git merge-file --ours 이 실해서
일을 따로따로 Merge 했다.
이런 의 동작을 원하지만 애초GitMerge 시도조차 하지 않는 자비 없는 옵션도 있다. “ours” Merge 이다.
Recursive Merge “ours옵션 과는 다.
이 작은 기적으로 거으로 Merge 한다. 양 브랜치를 부모로 는 새 Merge 을 만든다. 하지만, Their
브랜치는 참고하지 않는다. Our 브랜치의 코드를 그대로 사용하고 Merge 한 것처럼 기록할 뿐이다.
$ git merge -s ours mundo
Merge made by the 'ours' strategy.
$ git diff HEAD HEAD~
$
281
지금 있는 브랜Merge 과가 다지 않다는 것을 알 수 있다.
ours 을 이용해 이Merge가 되었다고 Git을 속이고 실제로는 Merge를 나중에 수한다. 예를 들어 release
브랜치을 만들고 여기에도 코드를 추가했다. 가 이것을 master 브랜치에도 Merge 하지만 아직은 하지 않았다.
master 브랜치에서 bugfix 브랜치를 만들어 버그를 수정하고 이것을 release 브랜치에도 적용
(Backport)한다. bugfix 브랜치를 release 브랜치로 Merge 하고 이포함된 master 브랜치에도 merge -s
ours 명령으로 Merge . 게 하면 나중에 release 브랜치를 Merge 할 때 버그 수정에 대한 커으로
일어나지 않게할 수 있다.
서브트리 Merge
Merge 의 개념은 프로젝트 개가 있을 때 한 프로젝트를 다른 프로젝트의 하위 디렉토리하여 사용하는
것이다. Merge 으로 서(Subtree)를 사용하는 경우 Git똑똑하게 서찾아인 프로젝트로
프로젝트의 내용을 Merge 한다.
한 저소에 전히 다른 프로젝트의 모트 저소를 추가하고 데이터를 가져와Merge 까지 하는 과정을 살펴보자.
Rack 프로젝트 재 프로젝트에 추가한다. Rack 프로젝트의 모트 저소를 재 프로젝트의 모트로 추가하고
Rack 프로젝트의 브랜히스토리를 가져와(Fetch) 인한다.
$ git remote add rack_remote https://github.com/rack/rack
$ git fetch rack_remote --no-tags
warning: no common commits
remote: Counting objects: 3184, done.
remote: Compressing objects: 100% (1465/1465), done.
remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
Receiving objects: 100% (3184/3184), 677.42 KiB | 4 KiB/s, done.
Resolving deltas: 100% (1952/1952), done.
From https://github.com/rack/rack
Ê* [new branch] build -> rack_remote/build
Ê* [new branch] master -> rack_remote/master
Ê* [new branch] rack-0.4 -> rack_remote/rack-0.4
Ê* [new branch] rack-0.9 -> rack_remote/rack-0.9
$ git checkout -b rack_branch rack_remote/master
Branch rack_branch set up to track remote branch
refs/remotes/rack_remote/master.
Switched to a new branch "rack_branch"
(- git fetch rack_remote 명령의 과에서 warning: no common commits 시지를 주목해한다.)
Rack 프로젝트의 브랜치인 rack_branch 를 만들었다. 원 프로젝트는 master 브랜치에 있다. checkout 명령으로
두 브랜치를 이동하면 전다른 프로젝트가 한 저소에 있는 것처럼 보인다.
282
$ ls
AUTHORS KNOWN-ISSUES Rakefile contrib lib
COPYING README bin example test
$ git checkout master
Switched to branch "master"
$ ls
README
상당히 요상한 방식으로 Git을 활용한다. 소의 브랜치가 은 프로젝트가 수도 있다. Git에서는 전다른
브랜치를 쉽게 만들 수 있다. 물론 게 사용하는 경우는 드.
Rack 프로젝트를 master 브랜치의 하위 디렉토리로 만들 수 있다. 이는 git read-tree 명령을 사용한다. read-
tree 명령과 이 저수명령에 관련된 많은 내용은 Git의 내부에서 다. 하자면 read-tree 명령은 어
브랜치로부터 루트 트어서 Staging Area렉토리로 가온다. master 브랜치로 다시 Checkout
하고 rack_branch 브랜치를 rack 이라는 master 브랜치의 하위 디렉토리로 만들어보자.
$ git read-tree --prefix=rack/ -u rack_branch
이제 커하면 Rack 프로젝트의 모든 일이 Tarball 축파일을 어서 소스코드를 포함한 것 이 커에 새로
추가된다. 게 쉽게 한 브랜치의 내용을 다른 브랜치에 Merge 수 있다는 지 않은가? Rack 프로젝트가
데이트되면 Pull 해서 master 브랜치도 적용할 수 있을까?
$ git checkout rack_branch
$ git pull
위의 명령을 실하고 데이트된 과를 master 브랜치로 다시 Merge 한다. Recursive Merge 략 옵션
-Xsubtree 옵션--squash 옵션을 함사용하면 동일한 커밋 메시지로 데이트할 수 있다. (Recursive
이지만 명을 위해서 사용한다)
$ git checkout master
$ git merge --squash -s recursive -Xsubtree=rack rack_branch
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested
위 명령을 실하면 Rack 프로젝트에서 경된 모든 부분이 master 브랜치로 영되고 커비가 된다. 대로
rack 하위 디렉토리에서 경한 내용을 rack_branch Merge 하는 것도 가하다. 경한 것을 에게
보내거나 UpstreamPush 한다.
이런 방식은 서(에서 자세하게 다)을 사용하지 않고 서관리하는 또 다른 크플로이다.
에 다른 프로젝트까지 유지하면서 서Merge 으로 데이트도 할 수 있다. 프로젝트에 요한 코드를
한 저소에서 관리할 수 있다. 다만, 게 저소를 관리하는 방법은 저소를 다루기 좀 복잡하고 합할 때 실수하기
쉽다. 한 저소로 Push 해버성도 있다.
283
diff 명령으로 rack 하위 디렉토리와 rack_branch 이를 볼 때도 이상하다. Merge 하기 전에 두 차이를 보고
어도 diff 명령을 사용할 수 없다. 대신 git diff-tree 명령이 있다.
$ git diff-tree -p rack_branch
rack 하위 디렉토리Rack 프로젝트의 모트 저소의 master 브랜떤 차이가 있는지 살펴보고
수도 있다. 마지으로 Fetch 모트의 master 브랜하려면 아래와 같은 명령을 사용한다.
$ git diff-tree -p rack_remote/master
Rerere
git rerere 이다. “reuse recorded resolution이라고 해서 기록한 해책 재사용하기
의 이름이고 이름 그대로 동작한다. Git을 때 각 코드 를 어떻게 해했는지 기록을 해 었다가
나중에 이 나면 기록을 참고하여 자동으로 해한다.
이 기을 사용하면 재있는 시나오가 가하다. 문서에서 드는 예제 중 하나는 브랜치를 깔끔하게 Merge
하고 은데 Merge 은 많이 만들고 지 않을 때 사용하는 것이다. rerere 고 자주 Merge를 해서
하고 Merge 이전으로 돌아간다. 이 과정을 반복해서 기록을 아두rerere 은 나중에 한 Merge 할 때
기록을 참고한다. 자동으로 만한 부분을 다 해해주시니 과 마음이 하다.
브랜치를 Rebase 할 때도 은 전을 사용할 수 있다. 기록을 참고하여 GitRebase 할 때 발생한
대한 해한다. 들을 해하고 Merge 했는데 다시 Rebase 하기로 마음을 바을 때
요 없다.
또 다른 상을 생각해보자. 가를 개토픽 브랜치가 여러 개 있을 때 이것을 스트 브랜치에 전부 다 Merge
한다. Git 프로젝트 자에서 자주 이게 한다. 스트가 실하면 해당 Merge소하고 스트가 실토픽
브랜치만 빼고 다시 Merge한다. 은 다시 으로 해하지 않도 된다.
rerere 은 간아래 명령으로 정하여 활성한다.
$ git config --global rerere.enabled true
소에 .git/rr-cache 렉토리를 만들어 기수도 있다. config 명령을 사용하는 방법깔끔하고
Global정할 수도 있다.
한 예제를 하나 더 살펴보자. 위에서 살펴예제하다. 아래와 같hello.rb 일 하나가 있다.
#! /usr/bin/env ruby
def hello
Ê puts 'hello world'
end
284
이전 예제가지로 한 브랜치에서는 “hello“hola” 로 바. 고 다른 브랜치에서는 “world”
“mundo로 바.
이런 상에서 이 두 브랜치를 Merge 하면 당이 발생한다.
$ git merge i18n-world
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Recorded preimage for 'hello.rb'
Automatic merge failed; fix conflicts and then commit the result.
Merge 명령을 실과에 Recorded preimage for FILE 라는 과를 겨봐한다. 이 없으면
소처럼 그이 난다. 지금은 rerere 때문에 가지 정보를 더 출력했다. git status 명령을
해서 어떤 파일에 이 발생했는지 인한다.
$ git status
# On branch master
# Unmerged paths:
# (use "git reset HEAD <file>..." to unstage)
# (use "git add <file>..." to mark resolution)
#
# both modified: hello.rb
#
git rerere status 명령으로 일을 인할 수 있다.
285
$ git rerere status
hello.rb
git rerere diff 명령으로 해중인 상인할 수 있다. 마나 해했는지 비해서 보여.
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,11 @@
Ê#! /usr/bin/env ruby
Êdef hello
-<<<<<<<
- puts 'hello mundo'
-=======
+<<<<<<< HEAD
Ê puts 'hola world'
->>>>>>>
+=======
+ puts 'hello mundo'
+>>>>>>> i18n-world
Êend
rerere 에 포함된 것은 니지만 git ls-files -u 명령으로 이전//대상 버전의 해시를 인할 수도 있다.
$ git ls-files -u
100644 39804c942a9c1f2c03dc7c5ebcd7f3e3a6b97519 1 hello.rb
100644 a440db6e8d1fd76ad438a49025a9ad9ce746f581 2 hello.rb
100644 54336ba847c3758ab604876419607e9443848474 3 hello.rb
이제는 puts 'hola mundo' 내용으로 을 해하자. 마지으로 git rerere diff 명령을 실하면
rerere가 기록할 내용을 인할 수 있다.
286
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,7 @@
Ê#! /usr/bin/env ruby
Êdef hello
-<<<<<<<
- puts 'hello mundo'
-=======
- puts 'hola world'
->>>>>>>
+ puts 'hola mundo'
Êend
하게 해서 Githello.rb 일에서 이 발생했을 때 한쪽엔 “hello mundo이고 다른 한에는 “hola
world” 이면 이를 “hola mundo로 해한다.
이제 이 일을 해한 것으로 시한 다음에 커한다.
$ git add hello.rb
$ git commit
Recorded resolution for 'hello.rb'.
[master 68e16e5] Merge branch 'i18n'
고 나면 "Recorded resolution for FILE" 이라는 시지를 과에서 볼 수 있다.
287
이제 Merge를 되돌리Rebase를 해서 master 브랜치에 보자. Reset 히 알고 가기에서 살펴대로 git
reset 명령을 사용하여 브랜치가 가키는 커을 되돌린.
$ git reset --hard HEAD^
HEAD is now at ad63f15 i18n the hello
Merge 하기 이전 상돌아왔다. 이제 토픽 브랜치를 Rebase 한다.
$ git checkout i18n-world
Switched to branch 'i18n-world'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: i18n one word
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Resolved 'hello.rb' using previous resolution.
Failed to merge in the changes.
Patch failed at 0001 i18n one word
예상대로 Merge 했을 때와 같이 발생한다. 하지만, Rebase를 실과에 Resolved 'hello.rb' using
previous resolution 시지가 있다. 일을 열어보면 이이 해된 것을 볼 수 있다. 일 어디에도
이 발생했다는 시를 찾아볼 수 없다.
288
#! /usr/bin/env ruby
def hello
Ê puts 'hola mundo'
end
git diff 명령을 실해보면 Git이 자동으로 해과도 인할 수 있다.
$ git diff
diff --cc hello.rb
index a440db6,54336ba..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
Ê #! /usr/bin/env ruby
Ê def hello
- puts 'hola world'
Ê- puts 'hello mundo'
++ puts 'hola mundo'
Ê end
git checkout 명령으로 이 발생한 시의 상일 내용을 되돌릴 수도 있다.
289
$ git checkout --conflict=merge hello.rb
$ cat hello.rb
#! /usr/bin/env ruby
def hello
<<<<<<< ours
Ê puts 'hola world'
=======
Ê puts 'hello mundo'
>>>>>>> theirs
end
Merge에서 이러한 명령을 사용하는 예제를 보았다. 이때 git rerere 명령을 실하면 이 발생한 코드를
자동으로 다시 해한다.
$ git rerere
Resolved 'hello.rb' using previous resolution.
$ cat hello.rb
#! /usr/bin/env ruby
def hello
Ê puts 'hola mundo'
end
제로 이 발생한 상으로 되돌리rerere 명령으로 자동으로 을 해했다. 이제 을 해일을
추가하고 Rebase하기만 하면 된다.
$ git add hello.rb
$ git rebase --continue
Applying: i18n one word
이처럼 여러 Merge 하거나, Merge 지 않으면서도 토픽 브랜치를 master 브랜치의 신 내용으로
유지하거나, Rebase를 자주 한다면 rerere 는 게 여러모로 과 마음에 도움이 된다.
Git으로 버그
Git에는 버전관리 능 말고도 프로젝트를 디버하기 위해 사용할 좋은 기고 있다. Git히 유해서 어
형식의 프로젝트에나 사용할 수 있다. 문제를 일으인이나 버그를 쉽게 을 수 있도록 도와준.
파일 어노테이션(Blame)
버그를 을 때 저 그 코드가 , 제 추가했는지 알고 을 것이다. 이때는 일 어노을 활용한다.
마지으로 커한 사람이 누구인지, 제 마지으로 커했는지 볼 수 있다. 떤 메소드에 버그가 있으면 git blame
명령으로 그 소드의 각 라인을 제 마지으로 고는지 찾아수 있다.
290
다음 예제는 git blame 명령을 사용하여 어이나 커저자가 스 커Makefile 각 라인을 수정했는지
인해보고자 한다. -L 옵션을 사용하여 전체 파일이 니라 69 라인부터 82 라인까지 제한하여 부분적으로 인할 수도
있다.
$ git blame -L 69,82 Makefile
b8b0618cf6fab (Cheng Renquan 2009-05-26 16:03:07 +0800 69) ifeq
("$(origin V)", "command line")
b8b0618cf6fab (Cheng Renquan 2009-05-26 16:03:07 +0800 70)
KBUILD_VERBOSE = $(V)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) ifndef
KBUILD_VERBOSE
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73)
KBUILD_VERBOSE = 0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75)
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 76) ifeq
($(KBUILD_VERBOSE),1)
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 77) quiet =
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 78) Q =
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 79) else
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 80) quiet=quiet_
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 81) Q = @
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 82) endif
첫 항목은 그 라인을 마지으로 수정한 커SHA-1 이다. 그 다음 목은 , 제 그 라인을 커했는지
보여. , 제 커했는지 쉽게 을 수 있다. 일의 라인 내용을 보여.
^1da177e4c3f4 금할 ^ 시가 어 있으면 그 커에서 해당 라인이 처음 커됐다는 것을 의한다.
그러니까 해당 라인들은 처음 커한 후 경된 적이 없다. 지금까지 커을 가리킬 ^ 기호의 사용을 적어도 세 가지
이상 배기 때문에 갈릴 수 있으니 어노에서의 의동하지 .
Git일 이름을 경한 이력을 도로 기록해지 않는다. 하지만, 이 정보들은 각 스냅샷에 저되고 이 정보를
이용하여 경 이력을 만들어 수 있다. 그러니까 일에 생긴 변화는 무엇이든지 알수 있다. Git
어노을 분하여 코드들이 원떤 파일에서 커된 것인지 찾아준. 예를 들어 GITServerHandler.m
여러 개의 일로 했는데 그 중 한 일이 GITPackUpload.m 이라는 일이었다. 이 경우 -C 옵션으로
GITPackUpload.m 일을 추적해서 각 코드가 원떤 파일로 커된 것인지 알 수 있었다.
291
$ git blame -C -L 141,153 GITPackUpload.m
f344f58d GITServerHandler.m (Scott 2009-01-04 141)
f344f58d GITServerHandler.m (Scott 2009-01-04 142) - (void)
gatherObjectShasFromC
f344f58d GITServerHandler.m (Scott 2009-01-04 143) {
70befddd GITServerHandler.m (Scott 2009-03-22 144)
//NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m (Scott 2009-03-24 145)
ad11ac80 GITPackUpload.m (Scott 2009-03-24 146) NSString
*parentSha;
ad11ac80 GITPackUpload.m (Scott 2009-03-24 147) GITCommit
*commit = [g
ad11ac80 GITPackUpload.m (Scott 2009-03-24 148)
ad11ac80 GITPackUpload.m (Scott 2009-03-24 149)
//NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m (Scott 2009-03-24 150)
56ef2caf GITServerHandler.m (Scott 2009-01-05 151) if(commit) {
56ef2caf GITServerHandler.m (Scott 2009-01-05 152)
[refDict setOb
56ef2caf GITServerHandler.m (Scott 2009-01-05 153)
제나 코드가 커될 당시의 일이름을 알 수 있기 때문에 코드를 어떻게 해도 추적할 수 있다. 고 어
일에 적용해도 각 라인을 커할 당시의 일이름을 알 수 있다. 버그를 을 때 정유용하다.
이진 탐색
일 어노은 특정 이슈와 관련된 커는 데에도 좋다. 문제가 생을 때 의심스러운 커이 수, 수백 개에
는 경우 도대어디서부터 시작해할지 모를 수 있다. 이때는 git bisect 명령이 유용하다. bisect 명령은
히스토리를 이진 탐색 방법으로 좁혀 주기 때문에 이슈와 관련된 커대한 빠르찾아수 있도록 도와준.
코드를 운용 환경에 배포하고 난 후에 개발할 때 발하지 못한 버그가 있다고 보고았다. 그런데 그런 상이
발생하는지 아직 이해하지 못하는 상을 가정해보자. 해당 이를 다시 만들고 작하기 시작했는데 못됐는지
수 없다. bisect 명령을 사용하여 코드를 보는 게 좋다. git bisect start 명령으로 이
탐색을 시작하고 git bisect bad 를 실하여 재 커에 문제가 있다고 시를 기고 나서 문제가 없는 마지
git bisect good <good_commit> 명령으로 시한다.
$ git bisect start
$ git bisect bad
$ git bisect good v1.0
Bisecting: 6 revisions left to test after this
[ecb6e1bc347ccecc5f9350d878ce677feb13d3b2] error handling on repo
이 예제에서 마지으로 괜찮았던 커(v1.0)재 문제가 있는 커사이에 있는 커은 전부 12개이고 Git은 그
중간에 있는 커Checkout . 여기에서 해당 이구현됐는지 스트해보고 만가 있으면 그 중간 커
이전으로 위를 히고 이가 없으면 그 중간 커이후로 위를 좁힌. 를 발하지 못하면 git bisect
292
good 으로 이아직 없음을 알고 계속 진행한다.
$ git bisect good
Bisecting: 3 revisions left to test after this
[b047b02ea83310a70fd603dc8cd7a6cd13d15c04] secure this thing
재 문제가 있는 커과 지금 스트한 커사이에서 중간에 있는 커Checkout 됐다. 다시 스트해보고 이
있으면 git bisect bad 로 이가 있다고 알.
$ git bisect bad
Bisecting: 1 revisions left to test after this
[f71ce38690acf49c1f3c9bea38e09d82a5ce6014] drop exceptions table
이제 이를 처음 구현한 커았다. SHA-1 을 포함한 이 커의 정보를 인하고 수정된 일이 무엇인지
인할 수 있다. 이 문제가 발생한 시에 도대일이 있었는지 아래와 같이 살펴.
$ git bisect good
b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit
commit b047b02ea83310a70fd603dc8cd7a6cd13d15c04
Author: PJ Hyett <pjhyett@example.com>
Date: Tue Jan 27 14:48:32 2009 -0800
Ê secure this thing
:040000 040000 40ee3e7821b895e52c1695092db9bdc4c61d1730
f24d3c6ebcfc639b1a3814550e62d60b8e68a8e4 M config
이제 았으니까 git bisect reset 명령을 실서 이진 탐색을 시작하기 전으로 HEAD려놓는다.
$ git bisect reset
수백 개의 커들 중에서 버그가 만들어는 데 에 걸지 않는다. 프로젝트가 정상적으로 수되면 0
환하고 문제가 있으면 1환하는 스크트를 만든다면, git bisect 과정을 전히 자동으로 수할 수 있다.
bisect start 명령으로 이진 탐색에 사용할 위를 알려. 위에서 한 것처럼 문제가 있다고 는 커
문제가 없다고 는 커을 넘기면 된다.
$ git bisect start HEAD v1.0
$ git bisect run test-error.sh
문제가 생을 때까지 Checkout 할 때마다 test-error.sh 를 실한다. make 가 됐든지 make
tests 가 됐든지 어든 이스트를 실하여 는다.
293
서브모
프로젝트를 수하다 보면 다른 프로젝트를 함사용해하는 경우가 종종 있다. 사용할 다른 프로젝트는 외부에서
개발한 라이라던가 내부 여러 프로젝트에서 공통으로 사용할 라이일 수 있다. 이런 상에서 자주 생기는
프로젝트를 서로 개로 다루면서도 그 중 하나를 다른 하나 에서 사용할 수 있어한다는 것이다.
Atom 드를 제하는 웹사이트를 만드는 것을 예로 들어보자. Atom 드를 생성하는 코드는 접 작성하지 않고
라이를 가다 쓰기로 한다. 라이를 사용하려면 CPAN이나 Ruby gem 은 라이리 관리
사용하여 Shared 라이리 형태로 쓰거나 접 라이의 소스코드를 프로젝트로 사해서 사용할 수 있다.
Shared 라이를 사용하기에는 문제가 있다. 프로젝트를 사용하는 모든 환경에 라이치되어 있어하고
라이를 프로젝트에 간 수정해서 사용하고 배포하기가 어렵다. 또한, 라이소스코드를
프로젝트에 포함시키는 경우에는 라이Upstream 코드가 데이트됐을 때 Merge 하기가 어렵다.
Git의 서은 이런 문제를 다루는 도. Git 에 다른 Git 소를 디렉토리로 분는 것이
이다. 다른 독립Git 소를 Clone 해서 내 Git 에 포함할 수 있으며 각 저소의 커독립적으로
관리한다.
서브모시작하기
예제로 하위 프로젝트 여러 개를 가지는 프로젝트를 하나 만들어 서의 기을 살펴보자.
Git 소에 미리 준비된 모트 Git 소를 서로 추가해보자. 을 추가하는 명령으로 git
submodule add 에 추가할 저소의 URL. URL은 절대경로도 되고 상대경로도 된다. 예제로
“DbConnector” 라는 라이를 추가한다.
$ git submodule add https://github.com/chaconinc/DbConnector
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
적으로 서은 프로젝트 저소의 이름으로 디렉토리를 만든다. 예제에서는 “DbConnector” 라는 이름으로
만든다. 명령의 마지에 원하는 이름을 어 다른 디렉토리 이름으로 서을 추가할 수도 있다.
을 추가하고 난 후 git status 명령을 실하면 가지 정보를 알 수 있다.
294
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
Ê (use "git reset HEAD <file>..." to unstage)
Ê new file: .gitmodules
Ê new file: DbConnector
.gitmodules 일이 만들어. 일은 서렉토리와 하위 프로젝트 URL정보를
일이다.
[submodule "DbConnector"]
Ê path = DbConnector
Ê url = https://github.com/chaconinc/DbConnector
개수만큼 이 목이 생. 일도 .gitignore 일처럼 버전을 관리한다. 다른 일처럼 Push 하고 Pull
한다. 이 프로젝트를 Clone 하는 사람은 .gitmodules 일을 보고 어프로젝트가 있는지 알 수 있다.
gitmodules 파일에 있는 URL은 조는 사이면 누구든지 Clone 하고 Fetch 할 수 있도록
접근할 수 있어한다.
예를 들어 다른 사람이 Pull을 하는 URL과 라이의 작Push 하는 URL이 서로 다른
이라면 Pull URL이 모든 사람에게 접URL이어한다. 이러면 서URL 정을
어쓰기 해서 사용할 수 있는데 git config submodule.DbConnector.url
PRIVATE_URL 명령으로 다른 사람과는 다른 서URL을 사용할 수 있다. URL을 상대경로로
적을 수 있으면 상대경로를 사용하는 것이 .
.gitmodules 은 살펴고 이제 프로젝트 더에 대해 살펴보자. git diff 명령을 실시키면 로운 을 발
수 있다.
$ git diff --cached DbConnector
diff --git a/DbConnector b/DbConnector
new file mode 160000
index 0000000..c3f01dc
--- /dev/null
+++ b/DbConnector
@@ -0,0 +1 @@
+Subproject commit c3f01dc8862123d317dd46284b05b6892c7b29bc
GitDbConnector 렉토리를 서하기 때문에 해당 디렉토리 아래일 수정사접 추적하지
않는다. 대신 서렉토리통째로 특한 커으로 한다.
git diff --submodule 옵션을 더하면 서에 대해 더 자세히 나온다.
295
$ git diff --cached --submodule
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..71fc376
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "DbConnector"]
+ path = DbConnector
+ url = https://github.com/chaconinc/DbConnector
Submodule DbConnector 0000000...c3f01dc (new submodule)
이제 하위 프로젝트를 포함한 커을 생성하면 아래와 같과를 인할 수 있다.
$ git commit -am 'added DbConnector module'
[master fb9093c] added DbConnector module
Ê2 files changed, 4 insertions(+)
Êcreate mode 100644 .gitmodules
Êcreate mode 160000 DbConnector
DbConnector 렉토리의 모드는 `160000`이다. Git에게 있어 160000 모드는 일적인 일이나 디렉토리니라
하다는 의.
으로, Push 한다.
$ git push origin master
서브모듈 포함한 프로젝트 Clone
을 포함하는 프로젝트를 Clone 하는 예제를 살펴. 이런 프로젝트를 Clone 하면 기적으로 서
렉토리렉토리이다.
296
$ git clone https://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
$ cd MainProject
$ ls -la
total 16
drwxr-xr-x 9 schacon staff 306 Sep 17 15:21 .
drwxr-xr-x 7 schacon staff 238 Sep 17 15:21 ..
drwxr-xr-x 13 schacon staff 442 Sep 17 15:21 .git
-rw-r--r-- 1 schacon staff 92 Sep 17 15:21 .gitmodules
drwxr-xr-x 2 schacon staff 68 Sep 17 15:21 DbConnector
-rw-r--r-- 1 schacon staff 756 Sep 17 15:21 Makefile
drwxr-xr-x 3 schacon staff 102 Sep 17 15:21 includes
drwxr-xr-x 4 schacon staff 136 Sep 17 15:21 scripts
drwxr-xr-x 4 schacon staff 136 Sep 17 15:21 src
$ cd DbConnector/
$ ls
$
분명히 DbConnector 렉토리는 있지만 비어 있다. 관련명령을 실전히 Clone 과정이
난다. git submodule init 명령을 실하면 서정보를 기으로 로환경일이 비된다. 이후
git submodule update 명령으로 서모트 저소에서 데이터를 가오고 서을 포함한 프로젝트의
재 스냅샷에서 Checkout 할 커정보를 가져와서 서프로젝트에 대한 Checkout을 한다.
$ git submodule init
Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector)
registered for path 'DbConnector'
$ git submodule update
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out
'c3f01dc8862123d317dd46284b05b6892c7b29bc'
DbConnector 렉토리는 마지으로 커을 했던 상원된다.
하지만, 은 과정을 더 간하게 실하는 방법도 있다. 인 프로젝트를 Clone 할 때 git clone 명령
--recurse-submodules 옵션이면 서을 자동으로 하고 데이트한다.
297
$ git clone --recurse-submodules https://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector)
registered for path 'DbConnector'
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out
'c3f01dc8862123d317dd46284b05b6892c7b29bc'
서브모듈 포함한 프로젝트 작업
이제 프로젝트에 포함된 서의 저소 데이터코드도 다 받아왔다. 인 프로젝트프로젝트를 오가며
팀원과 협업비가 되었다.
서브모업데이트하기
장 단순한 서사용 방법은 하위 프로젝트를 수정하지 않고 참만 하면서 신 버전으로 데이트하는 것이다.
한 예제로 이 경우를 살펴.
프로젝트를 신으로 데이트하려면 서렉토리에서 git fetch 명령을 실하고 git merge
명령으로 Upstream 브랜치를 Merge한다.
$ git fetch
From https://github.com/chaconinc/DbConnector
Ê c3f01dc..d0354fc master -> origin/master
$ git merge origin/master
Updating c3f01dc..d0354fc
Fast-forward
Êscripts/connect.sh | 1 +
Êsrc/db.c | 1 +
Ê2 files changed, 2 insertions(+)
인 프로젝트로 돌아와git diff --submodule 명령을 실하면 데이트된 서과 각 서에 추가된
을 볼 수 있다. 매번 --submodule 옵션을 쓰고 지 않다면 diff.submodule “log” 정하면 된다.
298
$ git config --global diff.submodule log
$ git diff
Submodule DbConnector c3f01dc..d0354fc:
Ê > more efficient db routine
Ê > better connection routine
여기서 커하면 서데이트된 내용으로 인 프로젝트에 적용된다. 다른 사람들이 데이트하면 적용된다.
신으로 데이트하는 더 방법도 있다. 렉토리에서 Fetch 명령과 Merge 명령을 실하지
git submodule update --remote 명령을 실하면 Git이 알서 서프로젝트를 Fetch 하고
데이트한다.
$ git submodule update --remote DbConnector
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
Ê 3f19983..d0354fc master -> origin/master
Submodule path 'DbConnector': checked out
'd0354fc054692d3906c85c3af05ddce39a1c0644'
이 명령은 기적으로 서소의 master 브랜치를 Checkout 하고 데이트를 수한다. 데이트할 대상
브랜치를 원하는 브랜치로 바수 있다. 예를 들어 DbConnector 소에서 데이트할 대상 브랜치를
“stable” 로 바다면 .gitmodules 일에 정하거나(일을 유하는 모에게 “stable” 브랜치가 적용)
개인 일인 .git/config 일에 정한다. .gitmodules 일에 정하는 방법을 알보자.
$ git config -f .gitmodules submodule.DbConnector.branch stable
$ git submodule update --remote
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
Ê 27cf5d3..c87d55d stable -> origin/stable
Submodule path 'DbConnector': checked out
'c87d55d4c6d4b05ee34fbc8cb6f7bf4585ae6687'
-f .gitmodules 옵션을 포함하지 않으면 이 정은 유하지 않고 사용자에게만 적용된다. 다른 사람과 유하는
소라면 브랜치를 추적하도록 정하는 것이 더 .
이제 git status 명령를 실하면 새로 데이트한 서“new commits” 가 있다는 걸 알 수 있다.
299
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: .gitmodules
Ê modified: DbConnector (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
일에 status.submodulesummary 목을 정하면 서경 사을 간히 보여.
$ git config status.submodulesummary 1
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
Ê (use "git add <file>..." to update what will be committed)
Ê (use "git checkout -- <file>..." to discard changes in working
directory)
Ê modified: .gitmodules
Ê modified: DbConnector (new commits)
Submodules changed but not updated:
* DbConnector c3f01dc...c87d55d (4):
Ê > catch non-null terminated lines
정하고 난 후 git diff 명령을 실해보자. .gitmodules 일이 경된 내용은 물론이거니와 업데이트해서
요가 생소의 경 내용을 인할 수 있다.
300
$ git diff
diff --git a/.gitmodules b/.gitmodules
index 6fc0b3d..fd1cc29 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
Ê[submodule "DbConnector"]
Ê path = DbConnector
Ê url = https://github.com/chaconinc/DbConnector
+ branch = stable
ÊSubmodule DbConnector c3f01dc..c87d55d:
Ê > catch non-null terminated lines
Ê > more robust error handling
Ê > more efficient db routine
Ê > better connection routine
에 실제로 커할 커들의 정보를 보기에는 괜찮방법이다. 으로 커한 후에 로그에서 위와 같
살펴보려면 git log -p 명령으로 볼 수 있다.
$ git log -p --submodule
commit 0a24cfc121a8a3c118e0105ae4ae4c00281cf7ae
Author: Scott Chacon <schacon@gmail.com>
Date: Wed Sep 17 16:37:02 2014 +0200
Ê updating DbConnector for bug fixes
diff --git a/.gitmodules b/.gitmodules
index 6fc0b3d..fd1cc29 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
Ê[submodule "DbConnector"]
Ê path = DbConnector
Ê url = https://github.com/chaconinc/DbConnector
+ branch = stable
Submodule DbConnector c3f01dc..c87d55d:
Ê > catch non-null terminated lines
Ê > more robust error handling
Ê > more efficient db routine
Ê > better connection routine
git submodule update --remote 명령을 실하면 기적으로 모든 데이트한다. 엄청
많을 땐 특정 서데이트하고자 할 수도 있는데 이때는 서의 이름을 지정해서 명령을 실한다.
301
서브모관리하기
인 프로젝트에서 서을 사용할 때 서에서도 가 작을 해할 상마든지 생수 있다.
프로젝트에서 작하는 도중에 이다(동시에 다른 서도 수정하거나). Git의 서을 사용하지
않는다면 다른 Dependency 관리 시스(Maven이나 Rubygem )을 사용할 수도 있다.
절에서는 서을 수정하고 그 내용을 은 커을 유지한 인프로젝트을 함께 관리하는
방법을 살펴.
소에서 git submodule update 명령을 실하면 Git은 서경 사데이트한다.
하지만, 소는 “Detached HEAD” 는다. 경 내용을 추적하는 로컬 브랜(예를
들자면 “master” )가 없다는 것이다. 경 내용을 추적하는 브랜치 없이 서에서 수정 작을 하게 되면 이후에
git submodule update 명령을 실했을 때 수정한 내용을 어버수 있다. 에서 수정사
추적하려면 다른 작이 좀 더 요하다.
브랜치를 추적하게 하려면 할 일이 가지다. 각 서렉토리로 가서 추적할 브랜치를 Checkout
하고 일을 시작해한다. 이후 서을 수정한 다음에 git submodule update --remote 명령을 실
Upstream 에서 새로운 커을 가온다. 이 커Merge 하거나 Rebase 하는 것은 선택할 수 있다.
저 서렉토리로 가서 브랜치를 Checkout 하자.
$ git checkout stable
Switched to branch 'stable'
여기서 “Merge” 를 해보자. update 명령을 쓸 때 --merge 옵션을 추가하면 Merge 하도록 지정할 수 있다. 아래
과에서 서버로부터 서경 사을 가져와Merge 하는 과정을 볼 수 있다.
$ git submodule update --remote --merge
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
Ê c87d55d..92c7337 stable -> origin/stable
Updating c87d55d..92c7337
Fast-forward
Êsrc/main.c | 1 +
Ê1 file changed, 1 insertion(+)
Submodule path 'DbConnector': merged in
'92c7337b30ef9e0893e758dac2459d07362ab5ea'
DbConnector 렉토리로 들어가면 새로 수정한 내용이 로컬 브랜stable 에 이Merge 된 것을 인할 수 있다.
이제 다른 사람이 DbConnector 라이를 수정해서 Upstream 소에 Push 한 상에서 우DbConnector
라이를 수정하면 무일이 일어나는지 살펴보자.
302
$ cd DbConnector/
$ vim src/db.c
$ git commit -am 'unicode support'
[stable f906e16] unicode support
Ê1 file changed, 1 insertion(+)
이제 서데이트하면 로소에서 수정한 것이 무엇인지 Upstream 소에서 수정된 것이 무엇인지 볼
수 있다. 이 둘을 합한다.
$ git submodule update --remote --rebase
First, rewinding head to replay your work on top of it...
Applying: unicode support
Submodule path 'DbConnector': rebased into
'5d60ef9bbebf5a0c1c1050f242ceeb54ad58da94'
--rebase 옵션이나 --merge 옵션을 지정하지 않으면 Git은 로컬 변경사을 무시하고 서버로부터 은 해당
의 버전으로 Reset을 하고 Detached HEAD 로 만든다.
$ git submodule update --remote
Submodule path 'DbConnector': checked out
'5d60ef9bbebf5a0c1c1050f242ceeb54ad58da94'
일이 이게 되더라도 문제가 된다. Reset이 된 서렉토리로 가서 작하던 브랜치를 Checkout 하고
origin/stable (니면 원하는 어모트 브랜치든)Merge 하거나 Rebase 하면 된다.
에 커하지 않은 경 사이 있는 로 서데이트하면 Git경 사을 가오지만,
하지 않은 작어쓰지 않는다.
$ git submodule update --remote
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 0), reused 4 (delta 0)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
Ê 5d60ef9..c75e92a stable -> origin/stable
error: Your local changes to the following files would be overwritten by
checkout:
Ê scripts/setup.sh
Please, commit your changes or stash them before you can switch branches.
Aborting
Unable to checkout 'c75e92a2b3855c9e5b66f915308390d9db204aca' in submodule
path 'DbConnector'
303
데이트 명령을 실했을 때 Upstream 소의 경 사이 나면 알려.
$ git submodule update --remote --merge
Auto-merging scripts/setup.sh
CONFLICT (content): Merge conflict in scripts/setup.sh
Recorded preimage for 'scripts/setup.sh'
Automatic merge failed; fix conflicts and then commit the result.
Unable to merge 'c75e92a2b3855c9e5b66f915308390d9db204aca' in submodule
path 'DbConnector'
이러면 서렉토리로 가서 을 해하면 된다.
서브모수정 사항 공유하기
재 서경된 내용을 포함하고 있다. 이 중 일부는 서데이트하여 Upstream 소에서
온 것이고 일부는 로에서 접 수정한 내용이다. 에서 수정한 것은 아직 공유하지 않았으무도 사용할 수
없는 코드이다.
$ git diff
Submodule DbConnector c87d55d..82d2ad3:
Ê > Merge from origin/stable
Ê > updated setup script
Ê > unicode support
Ê > remove unnecessary method
Ê > add new option for conn pooling
경사Push 하지 않은 인 프로젝트에서 커Push 하면 된다. 경 사Checkout
다른 사람은 서이 의존하는 코드를 어디서도 가져올 수 없는 상. 경사은 우
에만 있다.
이런 상사가 발생하지 않도록 하려면 인 프로젝트를 Push 하기 전에 서을 모Push 했는지 사하도록
Git에게 어보면 된다. git push 명령에 --recurse-submodules 옵션을 주고 이 옵션으로 “check
“on-demand” 정한다. “check는 간히 서의 로Push 되지 않은 상라면 재의 Push 명령도
하도록 하는 옵션이다.
304
$ git push --recurse-submodules=check
The following submodule paths contain changes that can
not be found on any remote:
Ê DbConnector
Please try
Ê git push --recurse-submodules=on-demand
or cd to the path and use
Ê git push
to push them to a remote.
예제에서 볼 수 있는 대로 이러한 상에서 다음으로 무엇을 해하는지 Git은 도움을 . 장 단순한 방법은 각
렉토리로 가서 접 일일이 Push를 해서 외부로 유하고 나서 인 프로젝트를 Push 하는 것이다. 옵션
상 적용되도록 하고 으면 git config push.recurseSubmodules check 명령으로 정한다.
옵션으로 정할 수 있는 다른 으로 “on-demand” 이 있는데, 으로 정하면 GitPush를 대신 시도한다.
$ git push --recurse-submodules=on-demand
Pushing submodule 'DbConnector'
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (9/9), 917 bytes | 0 bytes/s, done.
Total 9 (delta 3), reused 0 (delta 0)
To https://github.com/chaconinc/DbConnector
Ê c75e92a..82d2ad3 stable -> stable
Counting objects: 2, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 266 bytes | 0 bytes/s, done.
Total 2 (delta 1), reused 0 (delta 0)
To https://github.com/chaconinc/MainProject
Ê 3d6d338..9a377d1 master -> master
위에서 보Git인 프로젝트를 Push 하기 전에 DbConnector 로 들어가서 Push를 한다. 의 이유로
Push에 실한다면 인 프로젝트의 Push 또한 실하게 된다. git config
push.recurseSubmodules on-demand 명령으로 정할 수 있다.
서브모Merge 하기
다른 동시에 서을 수정하면 가지 문제에 하게 된다. 의 히스토리서 상위
프로젝트에 커했다면 사를 바로잡아야 한다.
305
의 커밋 두 개를 비했을 때 Fast-Forward Merge가 가한 경우 Git순히 마지선택한다.
하지만, Fast-Forward가 가하지 않으면 Git없이 Trivial Merge(Merge 기는 Merge)를 할 수 있다
해도 Merge 하지 않는다. 들이 분기됐다가 Merge 하는 경우 아래와 같과를 보게 된다.
$ git pull
remote: Counting objects: 2, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 2 (delta 1), reused 2 (delta 1)
Unpacking objects: 100% (2/2), done.
From https://github.com/chaconinc/MainProject
Ê 9a377d1..eb974f8 master -> origin/master
Fetching submodule DbConnector
warning: Failed to merge submodule DbConnector (merge following commits
not found)
Auto-merging DbConnector
CONFLICT (submodule): Merge conflict in DbConnector
Automatic merge failed; fix conflicts and then commit the result.
과를 재 상를 살펴다면 Git은 분기된 히스토리 브랜치를 았고 Merge요하다는 것을 알게 된다.
이 상“merge following commits not found”(Merge 을 수 없음)라는 시지로 표현하는데, 가 좀
이상하지만 그런지는 이어지는 내용으로 명한다.
이 문제를 해하기 위해 서이 어하는지 알아야 한다. 이상하게도 Git은 이를 위한 정보를 분히 주지
않는다. 히스토리에 있는 커SHA도 알려주지 않는다. 도 알내는 하다. git diff 명령을
하면 Merge 하려는 브랜치에 담긴 SHA를 알 수 있다.
$ git diff
diff --cc DbConnector
index eb41d76,c771610..0000000
--- a/DbConnector
+++ b/DbConnector
은 경우 eb41d76` 로컬 이고 `c771610` Upstream 있는 이다.
렉토리 가면 `eb41d76 을 가키고 있고 Merge 아직 이루어지지 않았다. 이 상에서
eb41d76 브랜치로 만들어 Merge 진행할 수 있다.
중요한 다른 SHA이다. Merge 할 대상이다. SHA 해시 을 명시하여 바로 Merge 할 수도
있고 대상이 되는 커을 새로 브랜치로 하나 만들어 Merge 할 수도 있다. Merge 밋 메시지를 위해서라도
후자를 추천한다.
문제를 해하기 위해 서렉토리로 이동해서 git diff 에서 나온 두 번째 SHA브랜치로 만들고 Merge
한다.
306
$ cd DbConnector
$ git rev-parse HEAD
eb41d764bccf88be77aced643c13a7fa86714135
$ git branch try-merge c771610
(DbConnector) $ git merge try-merge
Auto-merging src/main.c
CONFLICT (content): Merge conflict in src/main.c
Recorded preimage for 'src/main.c'
Automatic merge failed; fix conflicts and then commit the result.
실제 Merge 이 일어고 해한 다음 커했다. 이후 Merge 한 서과로 인 프로젝트를 데이트한다.
$ vim src/main.c
$ git add src/main.c
$ git commit -am 'merged our changes'
Recorded resolution for 'src/main.c'.
[master 9fd905e] merged our changes
$ cd ..
$ git diff
diff --cc DbConnector
index eb41d76,c771610..0000000
--- a/DbConnector
+++ b/DbConnector
@@@ -1,1 -1,1 +1,1 @@@
- Subproject commit eb41d764bccf88be77aced643c13a7fa86714135
Ê-Subproject commit c77161012afbbe1f58b5053316ead08f4b7e6d1d
++Subproject commit 9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a
$ git add DbConnector
$ git commit -m "Merge Tom's Changes"
[master 10d2c60] Merge Tom's Changes
을 해했다
인 프로젝트로 돌아간다.
SHA-1를 다시 사하고
난 서을 해한다.
Merge 과를 커한다.
좀 따라가기 어려수 있지만, 사실 그게 어려운 니다.
Git으로 이 문제를 해하는 로운 다른 방법이 있다. 위에서 커밋을 Merge Merge 커밋이 서
소에 존재하면 Git은 이 Merge 을 가한 해책으로 내놓는다. 가 이Merge 한 기록이 있기
307
때문에 Git은 이 Merge 을 제한다.
이런 이유에서 위에서 Merge 할 수 없다는 오류 메시지가 “merge following commits not found” (Merge
을 수 없음) 인 것이다. 이런 시지가 이상한 까가 이런 일을 한다고 상상이나 했이다.
위의 상에서 마Merge 을 하나 발했다면 아래와 같과를 볼 수 있다.
$ git merge origin/master
warning: Failed to merge submodule DbConnector (not fast-forward)
Found a possible merge resolution for the submodule:
Ê9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a: > merged our changes
If this is correct simply add it to the index for example
by using:
Ê git update-index --cacheinfo 160000
9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a "DbConnector"
which will accept this suggestion.
Auto-merging DbConnector
CONFLICT (submodule): Merge conflict in DbConnector
Automatic merge failed; fix conflicts and then commit the result.
Git이 제시한 해책은 마치 git add 한 것처럼 Index데이트해서 을 해하고 커하라는 것이다.
물론 제시한 해책을 따지 않을 수도 있다. 렉토리로 이동해서 경사인하고 Fast-forward
Merge를 한 후 Test 해보고 커할 수도 있다.
$ cd DbConnector/
$ git merge 9fd905e
Updating eb41d76..9fd905e
Fast-forward
$ cd ..
$ git add DbConnector
$ git commit -am 'Fast forwarded to a common submodule child'
와 같은 명령으로도 은 작을 수할 수 있다. 방법을 사용하면 Merge 에 해당하는 코드로 스트까지 해 볼
수 있으며, Merge 후에 서렉토리가 해당 코드로 데이트된다.
서브모
을 도와줄 몇 가지 을 소개한다.
서브모Foreach 여행
foreach 라는 서명령이 있어 한 에 각 서Git 명령을 내수 있다. 한 프로젝트 에 다수의 서
프로젝트가 포함된 경우 유용하게 사용할 수 있다.
308
예를 들어 여러 서에 걸하던 도중에 새로운 기을 추가하거나 버그 수정을 해하는 경우다. 아래와
은 명령으로 한꺼번에 모든 서Stash 명령을 실할 수 있다.
$ git submodule foreach 'git stash'
Entering 'CryptoLibrary'
No local changes to save
Entering 'DbConnector'
Saved working directory and index state WIP on stable: 82d2ad3 Merge from
origin/stable
HEAD is now at 82d2ad3 Merge from origin/stable
와 같이 명령을 실하고 나면 모든 서과 함브랜치로 이동해서 작비를 마치게 된다.
$ git submodule foreach 'git checkout -b featureA'
Entering 'CryptoLibrary'
Switched to a new branch 'featureA'
Entering 'DbConnector'
Switched to a new branch 'featureA'
히는가? 이 명령을 유용한 경우는 서을 포함한 인 프로젝트의 전diff 내용을 한꺼번과로 고자
하는 경우이다.
309
$ git diff; git submodule foreach 'git diff'
Submodule DbConnector contains modified content
diff --git a/src/main.c b/src/main.c
index 210f1ae..1f0acdc 100644
--- a/src/main.c
+++ b/src/main.c
@@ -245,6 +245,8 @@ static int handle_alias(int *argcp, const char
***argv)
Ê commit_pager_choice();
+ url = url_decode(url_orig);
+
Ê /* build alias_argv */
Ê alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));
Ê alias_argv[0] = alias_string + 1;
Entering 'DbConnector'
diff --git a/src/db.c b/src/db.c
index 1aaefb6..5297645 100644
--- a/src/db.c
+++ b/src/db.c
@@ -93,6 +93,11 @@ char *url_decode_mem(const char *url, int len)
Ê return url_decode_internal(&url, len, NULL, &out, 0);
Ê}
+char *url_decode(const char *url)
+{
+ return url_decode_mem(url, strlen(url));
+}
+
Êchar *url_decode_parameter_name(const char **query)
Ê{
Ê struct strbuf out = STRBUF_INIT;
위의 과로 알 수 있는 내용은 서에서 새 함수를 추가했고 인 프로젝트에서 추가한 함수를 호출한다는 내용이다.
예제로 살펴내용은 순한 예시일 뿐이지만 어떻게 foreach 명령을 유용하게 사용하는지 감 잡을 수 있을 것이다.
유용한 Alias
을 이용하는 명령은 대부분 이가 어서 Alias를 만들어 사용하는 것이 편하다. 일을 해 기
으로 모든 명령에 정하지 않고 쉽게 서을 사용할 때도 Alias는 유용하다. Alias정하는 방법Git
Alias에서 이다루었다. 여기에서는 서관련가지 유용한 Alias만 살펴.
$ git config alias.sdiff '!'"git diff && git submodule foreach 'git diff'"
$ git config alias.spush 'push --recurse-submodules=on-demand'
$ git config alias.supdate 'submodule update --remote --merge'
310
와 같정하면 git supdate 명령으로 간히 서데이트할 수 있고 git spush 명령으로 간
데이트가 요한지 인하며 인 프로젝트를 Push 할 수 있다.
서브모사용할 주의할 점들
적으로 서은 어렵지 않게 사용할 수 있지만, 의 코드를 수정하는 경우에는 주의해한다.
예를 들어 Checkout으로 브랜치를 경하는 경우 서이 포함된 작이라면 좀 하게 동작할 수 있다.
프로젝트에서 새 브랜치를 생성하고 Checkout 한 후 새로 서을 추가한다. 이후 다시 이전 브랜치로 Checkout
하면 서렉토리는 추적하지 않는 디렉토리게 된다.
$ git checkout -b add-crypto
Switched to a new branch 'add-crypto'
$ git submodule add https://github.com/chaconinc/CryptoLibrary
Cloning into 'CryptoLibrary'...
...
$ git commit -am 'adding crypto library'
[add-crypto 4445836] adding crypto library
Ê2 files changed, 4 insertions(+)
Êcreate mode 160000 CryptoLibrary
$ git checkout master
warning: unable to rmdir CryptoLibrary: Directory not empty
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
Ê (use "git add <file>..." to include in what will be committed)
Ê CryptoLibrary/
nothing added to commit but untracked files present (use "git add" to
track)
물론 추적하지 않는 디렉토리를 지우는 쉽다. 게 수동으로 지워야 한다는 게 이상한 것이다. 수동으로 디렉토리
지우고 다시 서을 추가했던 브랜치로 Checkout 하면 submodule update --init 명령을 실
의 코드가 나타난다(- 게 코드를 가오고 나면 Detached HEAD가 된다).
311
$ git clean -ffdx
Removing CryptoLibrary/
$ git checkout add-crypto
Switched to branch 'add-crypto'
$ ls CryptoLibrary/
$ git submodule update --init
Submodule path 'CryptoLibrary': checked out
'b8dda6aa182ea4464f3f3264b11e0268545172af'
$ ls CryptoLibrary/
Makefile includes scripts src
명령이 어려운 니지만, 다시 도 이상하다.
또 하나 주의 게 살펴볼 일은 서렉토리를 서교체하면서 브랜치간 이동하는 경우이다. 인 프로젝트에서
관리하던 서렉토리를 새 서교체할 때 주의를 기이지 않으면 Git어던지고 게 된다. 렉토리
교체하는 상을 살펴보자. 렉토리를 그지우고 바로 서을 추가한다면 오가 나타난다.
$ rm -Rf CryptoLibrary/
$ git submodule add https://github.com/chaconinc/CryptoLibrary
'CryptoLibrary' already exists in the index
와 같은 오를 해하려면 우CryptoLibrary 렉토리관리대상에서 제하고 나서 서을 추가한다.
$ git rm -r CryptoLibrary
$ git submodule add https://github.com/chaconinc/CryptoLibrary
Cloning into 'CryptoLibrary'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
위의 작master떤 브랜치에서 실한 상이다. 다시 master 브랜치로 Checkout 하게 되면
니라 서렉토리가 존재해하는 상이 되는데, 아래와 같은 오를 만나게 된다.
312
$ git checkout master
error: The following untracked working tree files would be overwritten by
checkout:
Ê CryptoLibrary/Makefile
Ê CryptoLibrary/includes/crypto.h
Ê ...
Please move or remove them before you can switch branches.
Aborting
물론 checkout -f 옵션여서 제로 브랜치를 Checkout 할 수 있지만, 에서 저하지 않은 내용을
돌릴 수 없게 어쓰기 때문에 주의 제 적용 옵션을 사용해한다.
$ git checkout -f master
warning: unable to rmdir CryptoLibrary: Directory not empty
Switched to branch 'master'
후에 다시 서을 추가했던 브랜치로 Checkout 하면 서렉토리 CryptoLibrary 는 비어 있다. git
submodule update 명령으로 서하더라도 서코드가 살나지 않을 수 있다. 때는
렉토리로 이동해서 git checkout . 명령을 실하면 서코드가 나타난다. 을 여러 개
사용하는 경우 submodule foreach 명령으로 한꺼번에 코드를 복구할 수 있다.
신 버전의 Git은 서의 커데이터도 인 프로젝트의 .git 렉토리에서 관리한다. 예전 버전의 Git과 달
이 포함된 디렉토리렸다 하더라도 기록해 데이터는 쉽게 을 수 있다.
이런 여러 도구와 을 사용한다면 간하고 효율적으로 인 프로젝트하위 프로젝트를 동시에 관리할 수
있다.
Bundle
에서 Git 데이터를 크를 거전송하는 일적인 방법(HTTP, SSH)을 다루었었다. 적으로 사용하
않지만, 유용한 방법이 하나 더 있다.
Git에는 “Bundle” 것이 있다. 데이터를 한 일에 아넣는 것이다. 방법은 다한 경우 유용하게 사용할 수 있다.
예를 들어 크가 불통인데 경사을 동에게 보, 을 나는데 보상의 이유로 로컬 네크에
접속하지 못할 때, 신 인터이스 비가 고을 때, 자기 용 서버에 접하지 못할 때, 가에게 수정사
일로 보내하는데 40이나 되는 커format-patch 로 보내고 지 않을 때를 예로 들 수 있다.
바로 이git bundle 이 한 이 되어. bundle 명령은 보git push 명령으로 려 보모든 것을
서 한 바이너리 파일로 만든다. 일을 이일로 보내거나 USB로 다른 사람에게 보내서 다른 저소에 어서
(Unbundle) 사용한다.
한 예제를 보자. 이 저소에는 커밋 두 개가 있다.
313
$ git log
commit 9a466c572fe88b195efd356c3f2bbeccdb504102
Author: Scott Chacon <schacon@gmail.com>
Date: Wed Mar 10 07:34:10 2010 -0800
Ê second commit
commit b1ec3248f39900d2a406049d762aa68e9641be25
Author: Scott Chacon <schacon@gmail.com>
Date: Wed Mar 10 07:34:01 2010 -0800
Ê first commit
이 저소를 다른 사람에게 통째로 보내고 은데 그 사람의 저소에 Push 한이 없거나, Push 하고 지 않을
, git bundle create 명령으로 Bundle을 만들 수 있다.
$ git bundle create repo.bundle HEAD master
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (6/6), 441 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)
repo.bundle 이라는 이름의 일을 생성할 수 있다. 일에는 이 저소의 master 브랜치를 다시 만드는 데
요한 모든 정보가 다 들어 있다. bundle 명령으로 모든 Refs를 포함하거나 Bundle에 포함할 특정 간의 커
지정할 수 있다. Bundle을 다른 에서 Clone 하려면 위의 명령처럼 HEAD Refs를 포함해한다.
repo.bundle 일을 다른 사람에게 이일로 전송하거나 USB 드라이담아서 나수 있다.
repo.bundle 일을 일할 으로 어떻게든 보내놓으면 이 Bundle 일을 마치 URL에서 가온 것처럼 Clone
해서 사용할 수 있다.
$ git clone repo.bundle repo
Cloning into 'repo'...
...
$ cd repo
$ git log --oneline
9a466c5 second commit
b1ec324 first commit
Bundle 일에 HEAD Refs를 포함하지 않으려면 -b master 옵션을 써주거나 포함시킬 브랜치를 지정해한다.
지 않으면 Git은 어떤 브랜치로 Checkout 할지 알 수 없다.
이제 새 커세 개를 추가해서 운 저소를 다시 원Bundle을 만들었던 저소로 USB일이든 Bundle로 보내
새 커옮겨보자.
314
$ git log --oneline
71b84da last commit - second repo
c99cf5b fourth commit - second repo
7011d3d third commit - second repo
9a466c5 second commit
b1ec324 first commit
Bundle 일에 추가시위를 정해한다. 전송할 소한의 데이터를 알서 인하는
프로토콜과는 달Bundle 명령을 사용할 때는 수동으로 지정해한다. 소를 Bundle 일로 만들 수도
있지만, Bundle는 게 좋다. 예제에서는 로에서 만든 세 개의 커는다.
선 차찾아Bundle 일을 만들 수 있다. 위로 커키기에서 살펴대로 자를 사용하여 커
위를 지정할 수 있다. Clone 브랜치인 master에는 없던 세 개의 커어내려면
origin/master..master 또는 master ^origin/master 터를 쓰면 된다. log 명령으로 시해볼 수
있다.
$ git log --oneline master ^origin/master
71b84da last commit - second repo
c99cf5b fourth commit - second repo
7011d3d third commit - second repo
이제 Bundle 일에 포함할 커었으니 어보자. git bundle create 명령에 Bundle 일의 이름과
을 커위를 지정한다.
$ git bundle create commits.bundle master ^9a466c5
Counting objects: 11, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (9/9), 775 bytes, done.
Total 9 (delta 0), reused 0 (delta 0)
이제 디렉토리commits.bundle 일이 생. 일을 동에게 보내면 원의 저소에 일이 마나
진행되었든 간에 일 내용을 적용할 수 있다.
Bundle 일을 동았으면 원소에 적용하기 전에 무엇이 들어 있는지 살펴볼 수 있다. bundle
verify 명령으로 일이 바른 Git Bundle인가, 제대로 적용하는 데 요한 모든 히스토리재 저소에 있는가
인한다.
315
$ git bundle verify ../commits.bundle
The bundle contains 1 ref
71b84daaf49abed142a373b6e5c59a22dc6560dc refs/heads/master
The bundle requires these 1 ref
9a466c572fe88b195efd356c3f2bbeccdb504102 second commit
../commits.bundle is okay
에서 Bundle 일을 만들 때 커세 개로 만들지 않고 마지막 두 으로만 Bundle 일을 만들면 커
모자라기 때문에 Bundle을 만들었던 저소에 새 Bundle 일을 합수 없다. 이런 문제를 verify 명령으로
인할 수 있다.
$ git bundle verify ../commits-bad.bundle
error: Repository lacks these prerequisite commits:
error: 7011d3d8fc200abe0ad561c011c3852a4b7bbe95 third commit - second repo
제대로 만든 Bundle 일이라면 커을 가져와소에 합수 있다. 데이터를 가져올 Bundle 일에 어
브랜치를 포함하고 있는지 살펴보려면 아래와 같은 명령으로 인할 수 있다.
$ git bundle list-heads ../commits.bundle
71b84daaf49abed142a373b6e5c59a22dc6560dc refs/heads/master
에서 verify 명령을 실했을 때도 브랜치 정보를 인할 수 있다. 여기서 중요하게 을 부분은 fetch 명령이나
pull 명령으로 가져올 대상이 되는 브랜치를 Bundle 일에서 인하는 것이다. 예를 들어 Bundle 일의 master
브랜치를 작하는 저소의 'other-master' 브랜치로 가오는 명령은 아래와 같이 실한다.
$ git fetch ../commits.bundle master:other-master
From ../commits.bundle
Ê* [new branch] master -> other-master
이런 으로 작하던 저소의 'master' 브랜치에 어을 했든 상없이 Bundle 일로부터 커독립적으로
'other-master' 브랜치로 가져올 수 있다.
$ git log --oneline --decorate --graph --all
* 8255d41 (HEAD, master) third commit - first repo
| * 71b84da (other-master) last commit - second repo
| * c99cf5b fourth commit - second repo
| * 7011d3d third commit - second repo
|/
* 9a466c5 second commit
* b1ec324 first commit
git bundle 명령으로 데이터를 전송할 크 상이 여의치 않거나 쉽게 유할 수 있는 저소를 비하기 어려
316
때도 히스토리를 쉽게 유할 수 있다.
Replace
히스토리(은 데이터이스)에 일Git의 개는 기적으로 경할 수 없다. 하지만 경된 것처럼 보이게 하는
는 기어 있다.
Gitreplace 명령은 "을 때 상 다른 개로 보이게" 한다. 히스토리에서 어이 다른 커처럼
보이도록 할 때 이 명령이 유용하다(`git filter-branch`를 사용하여 전히스토리를 다시 작성할 요가 없는 것이다).
예를 들어 재 프로젝트의 히스토리대한 상. 히스토리를 둘로 나어서 새로 시작하는 개발자에게는
히스토리주 간개의 커으로 만들어서 제하고, 프로젝트 히스토리를 분할 사람에게는 전히스토리
하는 상을 생각해보자. replace 명령으로 간히스토리를 전히스토리의 마지부분에 연결해서 사용할
수 있다. 게 히스토리경하는 데도 커을 새로 쓰지 않는 훌륭한 기이다(Rebase를 생각해보자. 한 부모를
경하면 이후의 커은 모재작성된다).
와 같은 상을 한해보자. 히스토리가 어느 정도 여 있는 Git 소를 소로 분해서 하나는 신 커밋 몇
개만 유지하도록 하고 다른 하나는 전히스토리를 유지하기로 한다. 게 분히스토리를 커을 재작성하지
않고 replace 명령을 사용하여 연결한다.
아래 예제로 사용하는 저소는 히스토리에 커5개가 있다.
$ git log --oneline
ef989d8 fifth commit
c6e1e95 fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
예제의 히스토리를 둘로 나어보자. 하나는 번째부터 네 번째 까지 히스토리로 만들어 원의 히스토리를 그대로
유지한다. 다른 새 히스토리네 번째 과 다번째 만을 포함하도록 한다.
317
의 히스토리를 유지하는 히스토리를 만들기는 쉽다. 히스토리 상에 기준점잡아 브랜치를 만들고
히스토리를 유지할 모트 저소로 Push 하면 간히 해된다.
$ git branch history c6e1e95
$ git log --oneline --decorate
ef989d8 (HEAD, master) fifth commit
c6e1e95 (history) fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
318
history 브랜치를 새 저소에 master 브랜치로 Push 한다.
319
$ git remote add project-history https://github.com/schacon/project-
history
$ git push project-history history:master
Counting objects: 12, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (12/12), 907 bytes, done.
Total 12 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (12/12), done.
To git@github.com:schacon/project-history.git
Ê* [new branch] history -> master
히스토리를 유지하는 히스토리Push 했다. 이제 은 어려운 부분은 신 커만 유지하도록 히스토리를 중간에
고 새로 만드는 작이다. 새로 만든 히스토리와 히스토리를 나중에 연결해서 사용할 때 네 번째 연결하도록
한다. 따라서 새로 만든 히스토리네 번째 이후의 커만 유지한다.
$ git log --oneline --decorate
ef989d8 (HEAD, master) fifth commit
c6e1e95 (history) fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
이런 예제 은 경우 히스토리를 어떻게 연결하는지 명하는 커을 만들어 나중에 개발자든 누구든 전히스토리를 볼
수 있도록 하는 것이 좋다. 이런 내용과 함께 네 번째 이전의 상을 새 커을 하나 만들고 네 번째 이후 커
이 새 커위에 Rebase 하기로 한다.
으로 을 커선택하고 새 커을 만든다. 예제는 9c68fdc 해시 는 세 번째 이 된다. 번째
내용을 기네 번째 이후 커을 히스토리는다. commit-tree 명령을 사용해서 새 커
만든다. 명령에 트를 전달하면 부모 없는 새 커을 생성하여 해시 환한다.
$ echo 'get history from blah blah blah' | git commit-tree 9c68fdc^{tree}
622e88e9cbfbacfb75b5279245b9fb38dfea10cf
commit-tree 명령은 'Plumbing' 명령 중 하나다. 저수명령은 일적으로 접 사용할 일이
없다. 'Plumbing' 명령들은 주로 사용하는 고수Git 명령이 하는 작개어 수할 때
사용한다. 이 책에서 위의 예제처럼 특한 작을 위해 간저수명령을 사용하하지만
사용하지는 않는다. 다른 여러 저수명령을 사용하는 예제는 Plumbing 명령과 Porcelain 명령에서
인할 수 있다.
320
이제 네 번째 이후의 히스토리을 커비됐다. git rebase --onto 명령으로 네 번째 이후의 커을 새
Rebase 한다. --onto 옵션 뒤에 전달할 커아올릴 대상이 되는 커을 입력한다. 위에서 commit-tree
명령으로 은 커을 사용하고 Rebase의 기네 번째 의 부모 커, 번째 9c68fdc 해시를
전달한다.
$ git rebase --onto 622e88 9c68fdc
First, rewinding head to replay your work on top of it...
Applying: fourth commit
Applying: fifth commit
321
와 같Rebase 하고 나면 신 커만 유지하는 새로운 히스토리가 만들어. 새 히스토리의 가번째 에는
어떻게 이전 히스토리연결해서 인할 수 있는지 명하는 내용이 포함되게 된다. 게 생성한 새 히스토리를 새
모트 저소로 Push 한다. 고 나서 Clone 해서 히스토리를 살펴보면 가장 최근 밋 몇 개만 보이고 가
에는 히스토리연결하는 내용이 있게 된다.
이제 할을 바어 새 히스토리Clone 하고 전히스토리까지 인하고자 하는 작을 예로 들어보자.
히스토리로부터 분한 새 히스토리 위에서 원히스토리인하려면 우히스토리를 포함하는 모트 저소를
추가하고 히스토리Fetch 한다.
322
$ git clone https://github.com/schacon/project
$ cd project
$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
622e88e get history from blah blah blah
$ git remote add project-history https://github.com/schacon/project-
history
$ git fetch project-history
From https://github.com/schacon/project-history
Ê* [new branch] master -> project-history/master
와 같이 실하고 나면 master 브랜치에는 간한 히스토리신 커만 있다. project-
history/master 브랜치에는 원히스토리 가 있게 된다.
$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
622e88e get history from blah blah blah
$ git log --oneline project-history/master
c6e1e95 fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
히스토리연결하기 위해 git replace 명령을 사용하여 새 히스토리의 커이 원히스토리에 속한 커
키도록 할 수 있다. 예제에서는 새 히스토리'fourth commit’project-history/master 브랜치의
'fourth commit’터로 전달한다.
$ git replace 81a708d c6e1e95
이제 master 브랜치에서 히스토리회해보면 아래와 같은 히스토리가 된다.
$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
323
히스토리가 그하다. 연결네 번째 이후의 커을 재작성하지 않고도 replace 명령으로 간하게 히스토리
경했다. 경한 히스토리에서도 bisect blame 은 다른 Git 명령을 사용할 수 있다.
연결된 히스토리를 보면 replace 명령으로 커경했음에도 여전히 c6e1e95 해시가 니라 81a708d 해시로
나오는 것을 인할 수 있다. cat-file 명령으로 보면 c6e1e95 해시의 내용이 출력된다.
$ git cat-file -p 81a708d
tree 7bc544cf438903b65ca9104a1e30345eee6c083d
parent 9c68fdceee073230f19ebb8b5e7fc71b479c0252
author Scott Chacon <schacon@gmail.com> 1268712581 -0700
committer Scott Chacon <schacon@gmail.com> 1268712581 -0700
fourth commit
Replace 이전 네 번째 81a708d 해시의 부모는 622e88e 해시이로 위의 9c68fdce 로 나오는 내용은 경한
대상인 c6e1e95 해시의 내용이다.
324
게 히스토리연결하는 것 Replace 명령의 과는 Refs관리한다.
$ git for-each-ref
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit refs/heads/master
c6e1e95051d41771a649f3145423f8809d1a74d4 commit
refs/remotes/history/master
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit refs/remotes/origin/HEAD
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit refs/remotes/origin/master
c6e1e95051d41771a649f3145423f8809d1a74d4 commit
refs/replace/81a708dd0e167a3f691541c7a6463343bc457040
Replace 내용을 Refs관리한다는 쉽게 이 내용을 서버로 Push 하여 다른 팀원과 유할 수 있다는 것을 한다.
Replace하는 것이 유용하지 않을 수도 있다. 든 모든 팀원이 히스토리를 다운로드해하는데 이 나
하나? 하지만, 때는 Replace하는 것이 유용할 수도 있다.
Credential 저장소
SSH 프로토콜을 사용하여 모트 저소에 접할 때 Passphase 없이 생성한 SSH Key를 사용하면 사용자이름과
호를 입력하지 않고도 전하게 데이터를 주고을 수 있다. HTTP 프로토콜을 사용하는 경우는 매번
사용자이름과 호를 입력해한다.
히도 Git은 이매번 정보(Credential)를 입력하는 경우 인정보를 저고 자동으로 입력해주는
시스을 제한다. Git Credential 이 제하는 옵션아래와 같.
적으로 무런 정도 하지 않으면 어호도 저하지 않는다. 이 경우 인요한 때 매번
사용자이름과 호를 입력해한다.
“cache” 모드로 정하면 일정 시간 동안 메에 사용자이름과 은 인정보를 기한다. 이 정보를 Disk
하지는 않으며 에서도 15분 까지만 유지한다.
“store” 모드로 정하면 인정보를 Disk스트 일로 저하며 계속 유지한다. 계속 유지한다는
모트의 인정보를 경하지 않는 한 다시 인정보를 입력하지 않도 접할 수 있다는 이다. “store모드를
사용할 때 주의할 은 인정보가 사용자 렉토리 아래에 일스트 일로 저된다는 이다.
Mac에서 Git을 사용하는 경우 “osxkeychain모드를 사용하면 Mac에서 제하는 Keychain 시스
사용자이름과 호를 재 로그인 계정에 속하게 저한다. “store모드하면 인정보를 Disk에 저하고
정보가 만되지 않는 지만, Safari 라우저가 인정보를 저하는 것과 은 수으로 해서
한다는 이 다.
Windows 환경에서는 “Git Credential Manager for Windows.라는 Helper가 있다. “osxkeychain
Helper하게 동작하며 Windows Credential Store를 사용하여 전하게 인정보를 저한다.
https://github.com/Microsoft/Git-Credential-Manager-for-Windows 에서 다운로드 을 수 있다.
위에서 명한 여러 모드 중 하나를 아래와 같정할 수 있다.
325
$ git config --global credential.helper cache
추가 옵션을 지정할 수 있는 Helper도 있다. “store” Helper--file <path> 옵션을 사용하여 인정보를 저
스트 일의 위치를 지정한다. ~/.git-credentials 이다. “cache” Helper--timeout
<seconds> 옵션을 사용하여 제까지 인정보를 에 유지할지 정한다. “900” 15분이다.
경로가 다른 경로를 지정해서 인정보를 저하려면 아래와 같이 실한다.
$ git config --global credential.helper 'store --file ~/.my-credentials'
Helper를 여러개 어서 쓸 수도 있다. 요한 모트에 접할 때 Git은 인정보를 는데 Helper가 여러개
있으면 순서대로 는다. 대로 인정보를 저할 때는 정한 모든 모드에 저한다. 아래 예제는 번째 Path에 대해
정보를 거나 저에 실하면 두 번째 모드에 따라 에서만 인정보를 유지한다.
[credential]
Ê helper = store --file /mnt/thumbdrive/.git-credentials
Ê helper = cache --timeout 30000
뚜껑어보
실제로는 어떻게 동작하는지 살펴보자. GitCredential-Helper 시스의 기명령은 git credential 이다.
명령이 하위 명령이나 옵션, 표준입력으로 요한 정보를 입력받아 전달한다.
이 과정은 예제를 해 이해하는 편이 쉽다. Credential Helper를 사용하도록 정하고 mygithost 라는 호스트의
정보가 저된 상이다. 아래 예제는 “fill” 명령으로 Git이 특정 호스트에 대한 인정보를 으려는 과정을
보여.
326
$ git credential fill
protocol=https
host=mygithost
protocol=https
host=mygithost
username=bob
password=s3cre7
$ git credential fill
protocol=https
host=unknownhost
Username for 'https://unknownhost': bob
Password for 'https://bob@unknownhost':
protocol=https
host=unknownhost
username=bob
password=s3cre7
이 명령으로 인정보를 어오는 과정을 시작한다.
이제 Git-credential 명령은 표준 입력으로 사용자의 입력을 기다. 정보가 요한 대상의 프로토콜
호스트이름을 입력한다.
라인을 하나 입력하면 입력이 끝났다는 것을 의한다. 이제 입력한 내용에 해당하는 인정보를 응답한다.
Git-credential 명령이 전달은 내용으로 인정보를 찾아보고 으면 표준출력으로 은 정보를 응답한다.
물론 에 대한 인정보가 없을 수도 있다. 게 되면 Git이 사용자이름과 호를 사용자가 입력하도록 시지를
우고 도 입력는다. 입력을 다시 표준출력으로 응답한다.
Credential 시스은 사실 Git과 분독립적인 프로그을 실동작한다. 프로그을 실지는
credential.helper 에 따른다. 아래와 같정한다.
설정 결과
foo
git-credential-foo
foo -a --opt=bcd
git-credential-foo -a --opt=bcd
/absolute/path/foo -xyz
/absolute/path/foo -xyz
!f() { echo "password=s3cre7"; }; f
! 의 코드를 에서 실
따라서 위에서 살펴여러 Helper는 사실 git-credential-cache, git-credential-store 은 명령이다.
정을 해 이 명령들이 옵션이나 하위 명령을 받아서 실하게 한다. 이 명령의 일적인 형태“git-credential-foo
[args] <action>” 이다. git-credential 명령과 마가지로 표준입력/표준출력을 프로토콜로 사용하지만 처하는
(하위 명령)아래와 같이 다소 다.
get - 사용자이름과 호를 요하는
store - Helper에서 인정보를 저하는
327
erase - Helper에서 인정보를 제하는
store erase 은 따로 과를 출력할 요가 없다(Git과를 무시). get 과는 Git이 주의
해서 가다 사용하우 중요하다. Helper는 전달은 내용으로 인정보를 고 저된 인정보가 없다면
무런 과도 출력하지 않고 하면 된다. 적당한 인정보를 았을 때는 전달은 내용에 은 인정보를 추가하여
과로 응답한다. 과는 라인의 할당 문으로 성하며, Git은 이 과를 받아서 사용한다.
아래 예제는 위에서 살펴예제와 같은 내용으로 git-crediential 명령 대신 git-credential-store 명령을
접 사용한다.
$ git credential-store --file ~/git.store store
protocol=https
host=mygithost
username=bob
password=s3cre7
$ git credential-store --file ~/git.store get
protocol=https
host=mygithost
username=bob
password=s3cre7
git-credential-store Helper에게 인정보를 저하도록 한다. 할 인정보는 사용자이름이 “bob”,
호가 “s3cre7” 이다. 프로토콜과 호스트가 https://mygithost 일 때 사용한다.
한 인정보를 가온다. 미 아https://mygithost 모트 주소를 호스트프로토콜로 나
표준입력으로 전달하고 한 라인을 비운다.
git-credential-store 명령은 <1>에서 저한 사용자이름과 호를 표준출력으로 응답한다.
~/git.store 일의 내용은 사실 아래와 같.
https://bob:s3cre7@mygithost
순한 스트일로 인정보가 포함된 URL 형태로 저한다. osxkeychain 이나 wincred Helper를 사용하면
OS에서 제하는 좀 더 전한 저소에 인정보를 저한다. cache Helper의 경우 나름의 형식으로
정보를 저하고 다른 프로세스에서는 (의 내용을) 수 없다.
맞춤 Credential
git-credential-store 나 다른 명령도 독립된 프로그이다. 아무 스크트나 프로그Git Credential
Helper가 될 수 있다. Git이 제하는 Helper로도 분하지만 모든 경우를 커버하지 않는다. 예를 들어 어
정보는 팀 전유해한다. 배포에 사용하는 인정보가 그. 이 인정보는 유하는 디렉토리
고 사용한다. 이 인정보는 자주 경되기 때문에 로Credential 소에 저하지 않고 사용하고자 한다.
이런 경우라면 Git이 제하는 Helper로는 부하며 자신만의 맞춤 Helper요하다. 맞춤 Helper아래와 같
을 제한다.
328
1. 맞춤 Helper중해get 뿐이다. store erase 은 저하는 기이기 때문에 이
으면 깔끔하게 바로 한다.
2. 유하는 Credential 일은 git-credential-store 명령이 저하는 형식형식을 사용한다.
3. Credential 일의 위치는 기을 사용해도 되지만 일 경로를 넘수 있다.
예제로 보여주는 맞춤 HelperRuby로 작성한다. 하지만, 다른 어떤 언어를 사용해도 Git이 실할 수만 있다면
없다. 작성한 저Helper의 소스코드는 아래와 같.
#!/usr/bin/env ruby
require 'optparse'
path = File.expand_path '~/.git-credentials'
OptionParser.new do |opts|
Ê opts.banner = 'USAGE: git-credential-read-only [options] <action>'
Ê opts.on('-f', '--file PATH', 'Specify path for backing store') do
|argpath|
Ê path = File.expand_path argpath
Ê end
end.parse!
exit(0) unless ARGV[0].downcase == 'get'
exit(0) unless File.exists? path
known = {}
while line = STDIN.gets
Ê break if line.strip == ''
Ê k,v = line.strip.split '=', 2
Ê known[k] = v
end
File.readlines(path).each do |fileline|
Ê prot,user,pass,host =
fileline.scan(/^(.*?):\/\/(.*?):(.*?)@(.*)$/).first
Ê if prot == known['protocol'] and host == known['host'] and user ==
known['username'] then
Ê puts "protocol=#{prot}"
Ê puts "host=#{host}"
Ê puts "username=#{user}"
Ê puts "password=#{pass}"
Ê exit(0)
Ê end
end
명령 옵션을 처한다. 옵션으로는 Credential 일명이 들어온다. ~/.git-credentials 이다.
Helper 프로그get 만 처하며 Credential 일이 존재하는 경우만 처한다.
329
이후에는 라인이 나타때까지 표준입력으로부터 한 줄 읽는다. 각 라인을 하여 known 해시에 저하고
<4>응답에서 사용한다.
이 루프에서 Credential 일을 어서 <3>의 해시에 해당하는 정보를 는다. known 해시에서 프로토콜과 호스트
정보가 일치하는 경우 사용자이름과 호를 포함하여 과를 출력한다.
일을 git-credential-read-only 로 저하고 PATH 에 등록된 디렉토리 중 하나에 위치시키고 실한을
부여한다. Helper를 실하면 아래와 같.
$ git credential-read-only --file=/mnt/shared/creds get
protocol=https
host=mygithost
protocol=https
host=mygithost
username=bob
password=s3cre7
위에서 저일 이름이 “git-” 으로 시작하기 때문에 아래와 같이 간한 이름으로 정해서 사용할 수 있다.
$ git config --global credential.helper 'read-only --file
/mnt/shared/creds'
게 살펴대로 Credential 소를 요에 따라 맞춤 프로그을 작성해서 확장하는 것이 어렵지 않다. 스크트를
만들어 사용자나 팀의 가려운 부분을 수 있다.
요약
과 저소를 꼼꼼하게 관리하는 도를 살펴보았다. 문제가 생기면 바로 , , 무엇을 했는지 찾아한다.
고 프로젝트를 개고 을 때 사용하는 방법들도 배. 이제 Git 명령은 거의 모배운 것이다. 자들이 하루
서 자유게 사용했으면 좋.
330
Git맞춤
지금까지 Git이 어떻게 동작하고 Git을 어떻게 사용하는지 명했다. 이제 Git을 좀 더 쉽고 편하게 사용할 수 있도록
주는 도를 살펴. 에서는 저 많이 쓰이는 정 그시스명한다. 그 후에 Git을 내게
추어(Customize) . Git을 자신의 프로젝트에 추고 편하게 사용하자.
Git 설정하기
시작하기에서 git config 명령을 간히 사용했었다. git config 명령으로 제일 저 하게 되는 작은 이름과
일 주소를 정하는 것이다.
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
여기서는 이정하는 것 중에서 중요한 것만 가지 배운다.
Git은 내된 기본 규칙 지만, 정된 것이 있으면 그에 따른다는 을 생각해. Git
/etc/gitconfig 일을 는다. 일은 해당 시스에 있는 모든 사용자모든 저소에 적용되는 일이다.
git config 명령에 --system 옵션을 주면 이 일을 사용한다.
다음으로 ~/.gitconfig 일을 는다. 일은 해당 사용자에게만 적용되는 일이다. --global 옵션
주면 Git은 이 일을 사용한다.
마지으로 재 작중인 저소의 Git 렉토리에 있는 .git/config 일을 는다. 일은 해당 저소에만
적용된다. git config 명령에 --local 옵션을 적용한 것과 . (무런 옵션을 지정하지 않으면 Git
적으로 --local 옵션을 적용한다)
일에 중정이 있으면 명한 순서대로. 예를 들어 .git/config /etc/gitconfig
정이 들어 있다면 .git/config 에 있는 정을 사용한다.
일 일적인 스트일로 쉽게 고쓸 수 있다. git config 명령을 사용하는 것이 더
편하다.
라이트 설정
정이 영치는 대상에 따라 라이정과 서버 정으로 나볼 수 있다. 대부분은 개인작환경과 관련
라이정이다. Git에는 정거우 많은데, 여기서는 크플로를 관리하는 데 요한 것과 주로 많이
사용하는 것만 명한다. 지 못할 상에서나 유용한 옵션까지 다 포함하면 정할 게 무 많다. Git 버전마다
옵션다른데, 아래와 같이 실하면 치한 버전에서 사용할 수 있는 옵션을 모보여.
$ man git-config
331
옵션을 사용할 수 있는지 우 자세히 명하고 있다. http://git-scm.com/docs/git-config.html 이지에서도
은 내용을 볼 수 있다.
core.editor
Git은 편기를 ($VISUAL, $EDITOR 수로 )하지 않았거나 정한 편기를 을 수 없으면 vi 를 실한다.
할 때나 시지를 편할 때 정한 편기를 실한다. code.editor 정으로 편기를 정한다.
$ git config --global core.editor emacs
정하면 시지를 편할 때 환경수에 정한 편기가 니라 Emacs를 실한다.
commit.template
할 때 Git이 보여주는 커밋 메시지는 이 옵션정한 릿 일이다. 사용자 지정 커밋 템릿 시지가 주는
장점은 커밋 메시지를 작성할 때 일정한 스타일을 유지할 수 있다는 이다.
예를 들어 ~/.gitmessage.txt 일을 아래와 같이 만든다.
Subject line (try to keep under 50 characters)
Multi-line description of commit,
feel free to be detailed.
[Ticket: X]
밋 메시지 릿을 보면 커밋 메시지를 작성할 때 제목은 일정 이 이하로 게 하고(git log --oneline 으로
보기 좋게) 자세한 수정 내용은 한백 이후 서하도록 하고 버그 트시스이나 이슈 관리 시스을 쓸 경우
호를 적도록 유도하고 있는 것을 볼 수 있다.
일을 commit.template 정하면 Gitgit commit 명령이 실하는 편기에 이 시지를 기으로
.
$ git config --global commit.template ~/.gitmessage.txt
$ git commit
그러면 커할 때 아래와 같시지를 편기에 자동으로 워준.
332
Subject line (try to keep under 60 characters)
Multi-line description of commit,
feel free to be detailed.
[Ticket: X]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: lib/test.rb
#
~
~
".git/COMMIT_EDITMSG" 14L, 297C
소속 팀에 커밋 메시지 규칙이 있으면 그 규칙릿 일을 만들고 시스템 설정에 정해. Git이 그 일을
사용하도록 정하면 규칙을 따기가 워진.
core.pager
Gitlog diff 은 명령의 시지를 출력할 때 이지로 나어 보여. 으로 사용하는 명령은 less .
more 를 더 좋하면 more 라고 정한다. 이지를 나지 않으면 문자열로 정한다.
$ git config --global core.pager ''
이 명령을 실하면 Git든지 든지 과를 한 에 다 보여 .
user.signingkey
정은 내 작에 서명하기 에서 명했던 Annotated Tag를 만들 때 유용하다. 사용할 GPG 키를 정해 둘 수 있다.
아래처럼 GPG 키를 정하면 서명할 때 편하다.
$ git config --global user.signingkey <gpg-key-id>
git tag 명령을 실할 때 키를 생하고 서명할 수 있다.
$ git tag -s <tag-name>
333
core.excludesfile
Git에서 git add 명령으로 추적할 일에 포함하지 않을 일은 .gitignore 에 해당 을 적으면 된다고
무시하기에서 명했다.
한 저에서뿐 니라 어디에서라도 Git에 포함하지 않을 일을 정할 수 있다. 예를 들어 Mac을 쓰는 사람이라면
.DS_Store 일을 자주 보았을 것이다. EmacsVim를 쓰다 보면 이름 ~, .swp 둔 임일도 있다.
.gitignore 일처럼 무시할 일을 정할 수 있는데 ~/.gitignore_global 아래 내용으로
입력해
*~
.*.swp
.DS_Store
git config --global core.excludesfile ~/.gitignore_global 명령으로 정을 추가하면 더는
와 같일이 포함되지 않을 것이다.
help.autocorrect
명령어를 못 입력하면 Git시지를 아래와 같이 보여 .
$ git chekcout master
git: 'chekcout' is not a git command. See 'git --help'.
Did you mean this?
Ê checkout
Git은 어명령을 입력하려고 했을지 추해서 보여주하지만 접 실않는다. 그러나 help.autocorrect
1정하면 명령어를 못 입력해도 Git이 자동으로 해당 명령어를 찾아서 실.
$ git chekcout master
WARNING: You called a Git command named 'chekcout', which does not exist.
Continuing under the assumption that you meant 'checkout'
in 0.1 seconds automatically...
여기서 재는 것은 “0.1 seconds” 이다. 사실 help.autocorrect 정에 사용하는 1/10 위의 자를
나타. 50이라는 으로 정한다면 자동으로 고명령을 실할 때 Git5간 명령을 실하지 않고 기다려
수 있다.
334
터미
사람이 쉽게 인할 수 있도록 터과를 러로 출력할 수 있다. 와 관련옵션우 다하기
때문에 꼼꼼하게 정할 수 있다.
color.ui
Git은 기적으로 터에 출력하는 을 알색칠하지만, 색칠하는 기다면 한 가지 정만 해
면 된다. 아래와 같은 명령을 실하면 더는 색칠을 내지 않는다.
$ git config --global color.ui false
정의 기auto 로 터에 출력할 때는 색칠하지만, 과가 다이되거나 일로 출력되면 색칠하지
않는다.
always 정하면 터이든 다른 출력이든 상없이 색칠하여 내보. 대개 이 정해서 사용하지 않는다.
--color 옵션을 사용하면 제로 과를 색칠해서 내도록 할 수 있기 때문이다. 대부분은 기.
color.*
Git은 좀 더 꼼꼼하게 러를 정하는 방법을 제한다. 아래와 같정들이 있다. true, false, always
하나를 고를 수 있다.
color.branch
color.diff
color.interactive
color.status
또한, 옵션러를 접 지정할 수도 있다. 아래처럼 정하면 diff 명령에서 meta 정보의 포그라운드는 blue,
백그라운드는 black, 스트는 bold로 바뀐다.
$ git config --global color.diff.meta "blue black bold"
러는 normal, black, red, green, yellow, blue, magenta, cyan, white 중에서 고를 수 있다. 스트 속성은
bold, dim, ul (underline), blink, reverse 중에서 고를 수 있다.
다른 Merge, Diff 사용하기
Git에 들어 있는 diff 구 말고 다른 도로 바수 있다. 려한 GUI 로 바서 좀 더 편하게 을 해할 수
있다. 여기서는 PerforceMerge P4Merge정하는 것을 보여. P4Merge는 무인데다 괜찮.
335
P4Merge는 중요 플랫폼을 모지원하기 때문에 만한 환경이면 사용할 수 있다. 여기서는 MacLinux 시스
치하는 것을 보여. Windows에서 사용하려면 /usr/local/bin 경로만 Windows 경로로 바.
https://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools 에서
P4Merge를 내려는다. 그 후에 P4Merge 에 쓸 Wrapper 스크트를 만든다. 자는 Mac 사용자라서 Mac 경로를
사용한다. 시스이든 p4merge 치된 경로를 사용하면 된다. 예제에서는 extMerge 라는 Merge Wrapper
스크트를 만들고 이 스크트로 넘어오는 모든 아규먼트를 p4merge 프로그으로 넘.
$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/p4merge.app/Contents/MacOS/p4merge $*
diffWrapper도 만든다. 이 스크트로 넘어오는 아규먼트는 7개지만 그 중 2개만 Merge Wrapper
. Gitdiff 프로그에 넘주는 아규먼트는 아래와 같.
path old-file old-hex old-mode new-file new-hex new-mode
이 중에서 old-file new-file 만 사용하는 wrapper 스크트를 만든다.
$ cat /usr/local/bin/extDiff
#!/bin/sh
[ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5"
스크트에 실한을 부여한다.
$ sudo chmod +x /usr/local/bin/extMerge
$ sudo chmod +x /usr/local/bin/extDiff
Git config 일에 이 스크트를 모추가한다. 정해하는 옵션이 좀 많다. merge.tool 로 무Merge
사용할지, mergetool.*.cmd 로 실제로 어떻게 명령어를 실할지, mergetool.trustExitCode Merge
환하는 exit 코드가 Merge의 성여부를 나타내는지, diff.external diff 할 때 실할 명령어가
무엇인지를 정할 때 사용한다. git config 명령으로 정한다.
$ git config --global merge.tool extMerge
$ git config --global mergetool.extMerge.cmd \
Ê 'extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"'
$ git config --global mergetool.extMerge.trustExitCode false
$ git config --global diff.external extDiff
~/.gitconfig/ 일을 접 편해도 된다.
336
[merge]
Ê tool = extMerge
[mergetool "extMerge"]
Ê cmd = extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
Ê trustExitCode = false
[diff]
Ê external = extDiff
정을 하고 나서 아래와 같diff 명령어를 실한다.
$ git diff 32d1776b1^ 32d1776b1
diff 과가 터에 출력되는 대신 P4Merge가 실되어 아래처럼 Diff 과를 보여.
그림 143. P4Merge.
브랜치를 Merge 할 때 이 나면 git mergetool 명령을 실한다. 이 명령을 실하면 GUI 을 해
수 있도록 P4Merge를 실.
Wrapper를 만들어 정해면 다른 Diff, Merge 로 바기도 쉽다. 예를 들어, KDiff3를 사용하도록 extDiff
extMerge 스크트를 수정한다.
$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/kdiff3.app/Contents/MacOS/kdiff3 $*
337
이제부터 GitDiff 과를 보여주거나 을 해할 때 KDiff3 를 사용한다.
Merge Git미리 설정이 들어 있다. 서 추가로 스크트를 작성하거나 하는 정 없이 사용할 수 있는
것도 있다. 아래와 같은 명령으로 인해볼 수 있다.
$ git mergetool --tool-help
'git mergetool --tool=<tool>' may be set to one of the following:
Ê emerge
Ê gvimdiff
Ê gvimdiff2
Ê opendiff
Ê p4merge
Ê vimdiff
Ê vimdiff2
The following tools are valid, but not currently available:
Ê araxis
Ê bc3
Ê codecompare
Ê deltawalker
Ê diffmerge
Ê diffuse
Ê ecmerge
Ê kdiff3
Ê meld
Ê tkdiff
Ê tortoisemerge
Ê xxdiff
Some of the tools listed above only work in a windowed
environment. If run in a terminal-only session, they will fail.
Diff 로는 다른 것을 사용하지만, Merge 로는 KDiff3를 사용하고 은 경우에는 kdiff3 명령을 실경로로
아래와 같정하기만 하면 된다.
$ git config --global merge.tool kdiff3
extMerge extDiff 일을 만들지 않고 이Merge `kdiff3`정하고 Diff Git에 원들어
있는 것을 사용할 수 있다.
Formatting and Whitespace
협업할 때 는 소스 포(Formatting)백 문제는 하고 난해하다. 사이에 사용하는 플랫폼이 다를 때는 특히
더 심하다. 다른 사람이 보내온 Patch백 문자 하게 다를 . 기가 래 공백문자를 추가해
수도 있고 크로스-플랫폼 프로젝트에서 Windows 개발자가 라인 CR(Carriage-Return) 문자를 추가해 버렸을
338
수도 있다. Git에는 이 이가지 정이 있다.
core.autocrlf
Windows에서 개발하는 동료와 일하면 라인 바(New Line) 문자에 문제가 생. Windows는 라인 바문자로
CR(Carriage-Return)LF(Line Feed) 문자를 둘 다 사용하지만, MacLinuxLF 문자만 사용한다. 무것도
지만, 크로스 플랫폼 프로젝트에서는 성가신 문제다. Windows에서 사용하는 많은 편기가 자동으로 LF
스타일의 라인 바스타일을 CRLF로 바거나 Enter 키를 입력하면 CRLF 스타일을 사용하기 때문이다.
Git은 커할 때 자동으로 CRLFLF환해주고 대로 Checkout 할 때 LFCRLF환해 주는 기이 있다.
core.autocrlf 정으로 이 기수 있다. Windows에서 이 true정하면 Checkout 할 때 LF 문자가
CRLF 문자로 환된다.
$ git config --global core.autocrlf true
라인 바문자로 LF를 사용하는 LinuxMac에서는 Checkout 할 때 GitLFCRLF환할 요가 없다. 게다가
CRLF가 들어간 일이 저소에 들어 있어도 Git이 알서 고주면 좋을 것이다. core.autocrlf
input으로 정하면 커할 때만 CRLFLF환한다.
$ git config --global core.autocrlf input
정을 이용하면 Windows에서는 CRLF를 사용하고 Mac, Linux, 소에서는 LF를 사용할 수 있다.
Windows 플랫폼에서만 개발하면 이 기요 없다. 옵션false 라고 정하면 이 기지고 CR 문자도
소에도 저된다.
$ git config --global core.autocrlf false
core.whitespace
Git에는 백 문자를 다루는 방법으로 가지가 미리 정의있다. 가지는 기적으로 있지만 수 있고 나
가지는 꺼져 있지만 수 있다.
저 기적으로 있는 것을 살펴보자. blank-at-eol 는 각 라인 백이 있는지 , blank-at-eof
에 추가한 라인이 있는지 , space-before-tab 은 모든 라인에서 처음에 tab보다 백이 저 나오는지
는다.
적으로 꺼져 있는 나지 세 개는 indent-with-non-tab tab-in-indent cr-at-eol 이다.
intent-with-non-tab tab니라 백으로(tabwidth 정에 영) 시작하는 라인이 있는지 cr-
at-eol 은 라인 CR 문자가 있어도 괜찮다고 Git에 알는 것이다.
core.whitespace 옵션으로 이 가지 방법수 있다. 정에서 해당 옵션을 빼버거나 이름이 -
시작하면 기꺼진. 예를 들어, 다른 space-before-tab 옵션려면 아래와 같정한다.
339
trailing-space 옵션blank-at-eol 옵션blank-at-eof 옵션을 의한다.
$ git config --global core.whitespace \
Ê trailing-space,-space-before-tab,indent-with-non-tab,tab-in-indent,cr-
at-eol
또는 각 부분에 대해서 정을 할 수도 있다.
$ git config --global core.whitespace \
Ê -space-before-tab,indent-with-non-tab,tab-in-indent,cr-at-eol
git diff 명령을 실하면 Git은 이 정에 따라 사해서 러로 시해. 서 좀 더 쉽게 해서 커할 수
있다. git apply 명령으로 Patch를 적용할 때도 이 정을 이용할 수 있다. 아래처럼 명령어를 실하면 해당 Patch
백문자 정책에 들어는지 인할 수 있다.
$ git apply --whitespace=warn <patch>
니면 Git이 자동으로 고치도록 할 수 있다.
$ git apply --whitespace=fix <patch>
옵션git rebase 명령에서도 사용할 수 있다. 백 문제가 있는 커UpstreamPush 하기 전에
--whitespace=fix 옵션을 주고 Rebase 하면 Git은 다시 Patch를 적용하면서 백을 정한 대로 고.
서버 설정
서버 정은 많지 않지만, 꼭 짚고 넘어가하는 것이 개 있다.
receive.fsckObjects
GitPush 할 때마다 각 개SHA-1 는지 못된 개가 가키고 있는지 사하게 할 수 있다.
적으로 이 기이 동작하지 않게 정이 되어 있는데 개하데 상당히 시간이 걸기 때문에 Push 하는
시간이 늘어난다. 마나 늘어나는지는 저소 크기Push 하는 에 달렸다. receive.fsckOBjects true
정하면 GitPush 할 때마다 검증한다.
$ git config --system receive.fsckObjects true
정하면 Push 할 때마다 검증하기 때문에 라이트는 못된 데이터를 Push 하지 못한다.
receive.denyNonFastForwards
Push 한 커Rebase 해서 다시 Push 하지 못하게 할 수 있다. 브랜치를 Push 할 때 해당 모트 브랜치가
340
키는 커Push 하려는 브랜치에 없을 때 Push 하지 못하게 할 수 있다. 은 이런 정책이 좋고 git push
명령에 -f 옵션을 주면 제로 Push 할 수 있다.
receive.denyNonFastForwards 옵션Fast-forwardPush 할 수 없는 브랜치는 Push 하지 못한다.
$ git config --system receive.denyNonFastForwards true
사용자마다 다른 정책을 적용하고 으면 서버 을 사용해한다. 서버의 receive 으로 할 수 있고 이 도 이 에서
명한다.
receive.denyDeletes
receive.denyNonFastForwards 한 정책으로 receive.denyDeletes 라는 것이 있다. 정을
브랜치를 제하는 Push가 거절된다.
$ git config --system receive.denyDeletes true
이제 브랜치나 Tag제하는 Push는 거절된다. 무도 제할 수 없다. 모트 브랜치를 제하려면 으로
serverref 일을 제해한다. 고 사용자마다 다른 정책을 적용시키는 ACL을 만드는 방법도 있다. 방법
정책 구현하기 에서 다.
Git Attributes
렉토리와 파위로 다른 정을 적용할 수도 있다. 게 경로정하는 것을 Git Attribute 라고 부른다.
정은 .gitattributes 라는 일에 저하고 무 디렉토리에나 둘 수 있지만, 은 프로젝트 상위 디렉토리
. 고 이 일을 커하고 지 않으면 .gitattributes 니라 .git/info/attributes 일을
만든다.
AttributeMerge는 어떻게 할지, 스트가 일은 어떻게 Diff 할지, checkin/checkout 할 때 어떻게
할지 정해수 있다. 이 절에서는 정할 수 있는 Attribute가 어것이 있는지, 고 어떻게 정하는지 배우고
예제를 살펴.
바이리 파일
Attribute로 어떤 파일이 바이너리 파일인지 Git에게 알려수 있다. 적으로 Git은 어떤 파일이 바이너리 파일인지
알지 못한다. 하지만, Git에는 일을 어떻게 다하는지 알려주는 방법이 있다. 스트 일 중에서 프로그
생성하는 일에는 바이너리 파일과 배없는 일이 있다. 이런 일은 diff 할 수 없으니 바이너리 파일이라고 알려
한다. 대로 바이너리 파일 중에서 급 방법Git에 알려주면 diff 할 수 있는 일도 있다. 이어지는 내용으로 어떻게
정할 수 있는지 살펴보자.
341
바이리 파일로 설정
사실 스트 일이지만 만든 목적과 의도를 보면 바이너리 파일인 것이 있다. 예를 들어 MacXcode.pbxproj
일을 만든다. 일은 IDE 정 등을 디스크에 저하는 일로 JSON 이다. 모든 것이 ASCII스트
일이지만 실제로는 간한 데이터이스이기 때문에 스트 일처럼 할 수 없다. 서 여러 명이 이 일을
동시에 수정하고 Merge 할 때 diff가 도움이 된다. 일은 프로그고 쓰는 일이기 때문에 바이너리 파일처럼
하는 것이 .
모든 pbxproj 일을 바이너리일로 하는 정은 아래와 같. .gitattributes 일에 으면 된다.
*.pbxproj binary
이제 pbxproj 일은 CRLF 환이 적용되지 않는다. git show git diff 은 명령을 실할 때도 계를
하거나 diff를 출력하지 않는다.
바이리 파일 Diff 하기
Git은 바이너리 파일도 Diff 할 수 있다. Git AttributeGit이 바이너리 파일을 스트 포으로 환하고 그 과를
diff 명령으로 비하도록 하는 것이다.
저 이 기을 인에게 알려은 문제 중 하나인 Word 문서를 버전 관리하는 상을 살펴보자. 모든 사람이
Word가 가끔찍한 편기라고 하지만 하게도 모Word를 사용한다. Git 소에 고 이따금 커하는
것만으로도 Word 문서의 버전을 관리할 수 있다. 지만 git diff 를 실하면 아래와 같시지를 볼 수 있을
뿐이다.
$ git diff
diff --git a/chapter1.docx b/chapter1.docx
index 88839c4..4afcb7c 100644
Binary files a/chapter1.docx and b/chapter1.docx differ
일을 하나하나 까보지 않으면 버전이 가 다른지 알 수 없다. Git Attribute를 사용하면 이를 더 좋게 개할 수
있다. .gitattributes 일에 아래와 같은 내용을 추가한다.
*.docx diff=word
이것은 *.docx 일의 버전이 무엇이 다른지 Diff 할 때 “word” 터를 사용하라고 정하는 것이다. 그럼 “word”
터는 ? “word” 터도 정의해한다. Word 문서에서 사람이 을 수 있는 스트를 추출해주는 docx2txt
프로그을 사용하여 Diff에 이용한다.
docx2txt 프로그치해하는데 http://docx2txt.sourceforge.net 사이트에서 다운로드 할 수 있다.
INSTALL 부분의 치과정을 참고하여 치하고 에서 실할 수 있도록 정한다. Git에서 쓸 수 있도록
Wrapper 스크트를 docx2txt 라는 이름으로 아래와 같이 작성한다.
342
#!/bin/bash
docx2txt.pl "$1" -
chmod a+x 로 실한을 정해아래와 같Git 정을 추가한다.
$ git config diff.word.textconv docx2txt
이제 Git확장자가 .docx 일의 스냅샷Diff 할 때 “word” 터로 정의한 docx2txt 프로그을 사용한다.
프로그Word 일을 스트 일로 환해 주기 때문에 Diff 할 수 있다.
이 책의 1Word 일로 만들어서 Git고 나서 단락 하나를 수정하고 저하는 예를 살펴. 새로 단락을 하나
추가하고 나서 git diff 를 실하면 어디가 달려는지 인할 수 있다.
343
$ git diff
diff --git a/chapter1.docx b/chapter1.docx
index 0b013ca..ba25db5 100644
--- a/chapter1.docx
+++ b/chapter1.docx
@@ -2,6 +2,7 @@
ÊThis chapter will be about getting started with Git. We will begin at the
beginning by explaining some background on version control tools, then
move on to how to get Git running on your system and finally how to get it
setup to start working with. At the end of this chapter you should
understand why Git is around, why you should use it and you should be all
setup to do so.
Ê1.1. About Version Control
ÊWhat is "version control", and why should you care? Version control is a
system that records changes to a file or set of files over time so that
you can recall specific versions later. For the examples in this book you
will use software source code as the files being version controlled,
though in reality you can do this with nearly any type of file on a
computer.
+Testing: 1, 2, 3.
ÊIf you are a graphic or web designer and want to keep every version of an
image or layout (which you would most certainly want to), a Version
Control System (VCS) is a very wise thing to use. It allows you to revert
files back to a previous state, revert the entire project back to a
previous state, compare changes over time, see who last modified something
that might be causing a problem, who introduced an issue and when, and
more. Using a VCS also generally means that if you screw things up or lose
files, you can easily recover. In addition, you get all this for very
little overhead.
Ê1.1.1. Local Version Control Systems
ÊMany people's version-control method of choice is to copy files into
another directory (perhaps a time-stamped directory, if they're clever).
This approach is very common because it is so simple, but it is also
incredibly error prone. It is easy to forget which directory you're in and
accidentally write to the wrong file or copy over files you don't mean to.
git diff 명령의 과를 보면 “Testing: 1, 2, 3.부분이 추가된 것을 인할 수 있다. 물론 스트 형식 같전한
정보는 니지만 어든 유용하다.
방법으로 이일도 Diff 할 수 있다. 터로 EXIF 정보를 추출해서 이일을 비한다. EXIF 정보는 대부분의
일에 들어 있는 타데이터다. exiftool 프로그치하고 이일에서 타데이터 스트를
추출한다. 고 그 과를 Diff 해서 무엇이 달라는지 . 다음 내용을 .gitattributes 일로 저한다.
*.png diff=exif
Git에서 위 정을 사용하려면 다음과 정한다.
344
$ git config diff.exif.textconv exiftool
프로젝트에 들어 있는 이일을 경하고 git diff 를 실하면 아래와 같이 보여.
diff --git a/image.png b/image.png
index 88839c4..4afcb7c 100644
--- a/image.png
+++ b/image.png
@@ -1,12 +1,12 @@
ÊExifTool Version Number : 7.74
-File Size : 70 kB
-File Modification Date/Time : 2009:04:21 07:02:45-07:00
+File Size : 94 kB
+File Modification Date/Time : 2009:04:21 07:02:43-07:00
ÊFile Type : PNG
ÊMIME Type : image/png
-Image Width : 1058
-Image Height : 889
+Image Width : 1056
+Image Height : 827
ÊBit Depth : 8
ÊColor Type : RGB with Alpha
일의 크기해상도가 달라것을 쉽게 알 수 있다.
키워드 치환
SVN이나 CVS한 사람들은 해당 시스에서 사용하던 키드 치환(Keyword Expansion) 는다.
Git에서는 이것이 쉽지 않다. Git을 계하고 커하기 때문에 그 커에 대한 정보를 가지고 일을 수정할
수 없다. 하지만, Checkout 할 때 그 정보가 자동으로 일에 입되도록 했다가 다시 커할 때 제되도록 할 수 있다.
$Id$ 드를 으면 BlobSHA-1 을 자동으로 입한다. 드를 일에 으면 Git으로
Checkout 할 때 해당 BlobSHA-1 으로 교체한다. 여기서 할 것이 있다. 교체되는 은 커의 것이
니라 Blob 그 자SHA-1 이다. 다음 내용을 .gitattributes 일로 저한다.
*.txt ident
스트 할 일에 $Id$ 런스를 고 저한다.
$ echo '$Id$' > test.txt
Git은 이 일을 Checkout 할 때마다 SHA-1 입해.
345
$ rm test.txt
$ git checkout -- test.txt
$ cat test.txt
$Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $
하지만, 이것은 로 유용하지 않다. CVSSVN의 키드 치환(Keyword Substitution)을 써으면
(Datestamp)도 가했다는 것을 알고 있을 것이다. SHA는 그해시이고 식별할 수 있을 뿐이지 다른 것을 알려주
않는다. SHA만으로는 예전 것보다 새것인지 오된 것인지는 알 수 없다.
Commit/Checkout 할 때 사용하는 터를 접 만들어 쓸 수 있다. 에 따라 “clean“smudge터라고
부른다. ".gitattributes" 일에 정하고 일 경로마다 다른 터를 정할 수 있다. Checkout 할 때 일을 처하는
것이 “smudge터이고(“smudge” 터는 Checkout 할 때 실.) 할 때 처하는 터가 “clean” (“clean
터는 일을 Stage 할 때 실.) 터이다. 터로 할 수 있는 일은 무하다.
그림 144. “smudge” 터는 Checkout 할 때 실행.
346
그림 145. “clean” 터는 파일을 Stage 할 때 실행.
이 기은 사실 커밋 메시지를 위한 기이었지만 용한다면 커하기 전에 indent 프로그으로 C 코드 전부를
하는 기을 만들 수 있다. *.c 일에 대해 indent 터를 거치도록 .gitattributes 일에 정한다.
*.c filter=indent
아래처럼 “indent” 터의 smudgeclean이 무엇인지 정한다.
$ git config --global filter.indent.clean indent
$ git config --global filter.indent.smudge cat
*.c 일을 커하면 indent 프로그해서 커되고 Checkout 하면 cat 프로그Checkout된다. cat
은 입력된 데이터를 그대로 다시 내보내는 사실 무것도 하는 프로그이다. 정하면 모든 C 소스 일은
indent 프로그해 커된다.
이제 RCS처럼 $Date$ 를 치환하는 예제를 살펴보자. 이 기구현하려면 간한 스크트가 하나 요하다.
스크트는 $Date$ 드를 프로젝트의 마지일자로 치환한다. 표준 입력을 어서 $Date$ 드를 치환한다.
아래Ruby구현한 스크트다.
#! /usr/bin/env ruby
data = STDIN.read
last_date = `git log --pretty=format:"%ad" -1`
puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$')
git log 명령으로 마지정보를 표준 입력(STDIN)에서 $Date$ 스트찾아서 치환한다. 스크트는
자신이 편한 어로 만든다. 이 스크트의 이름을 expand_date 라고 고 실경로에 는다. dater 라는
347
Git 터를 정의한다. Checkout시 실하는 smudge 터로 expand_date 를 사용하고 커할 때 실하는 clean
터는 Perl을 사용한다.
$ git config filter.dater.smudge expand_date
$ git config filter.dater.clean 'perl -pe
"s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"'
Perl 코드는 $Date$ 스트에 있는 문자를 제거해서 원대로 원한다. 이제 터가 비됐으니 $Date$ 드가
들어 있는 일을 만들고 Git Attribute정하고 새 터를 시해보자.
date*.txt filter=dater
$ echo '# $Date$' > date_test.txt
하고 일을 다시 Checkout 하면 해당 키드가 적절히 치환된 것을 볼 수 있다.
$ git add date_test.txt .gitattributes
$ git commit -m "Testing date expansion in Git"
$ rm date_test.txt
$ git checkout date_test.txt
$ cat date_test.txt
# $Date: Tue Apr 21 07:26:52 2009 -0700$
이 기력해서 입대로 프로젝트를 맞춤 설정할 수 있다. .git attributes 일은 커하는 일이기
때문에 터 드라이버(여기서는 dater) 정이 되지 않은 사람에게도 배포된다. 물론 dater 정이 안 돼 있는
사람에게는 에러가 난다. 터를 만들 때 이런 예외 상도 고려해서 동작하게 해한다.
저장소 트하기
프로젝트를 스포트해서 를 만들 때도 Git Attribute가 유용하다.
export-ignore
를 만들 때 제외할 일이나 디렉토리가 무엇인지 정할 수 있다. 특정 디렉토리일을 프로젝트에는
포함하고 에는 포함하고 지 않을 때 export-ignore Attribute를 사용한다.
예를 들어 test/ 렉토리스트 일이 있다고 하자. tar 일로 어서 스포트할 때 스트 일은 포함하지
않는다. Git Attribute 일에 아래 라인을 추가하면 스트 일은 무시된다.
test/ export-ignore
348
git archive 명령으로 tar 일을 만들면 test 렉토리에 포함되지 않는다.
export-subst
를 만들어서 배포할 때도 git log 은 포규칙을 적용할 수 있다. export-subst Attribute정한
일들의 키드가 치환된다.
git archive 명령을 실할 때 자동으로 마지타데이터가 자동으로 입되게 할 수 있다. 예를 들어
.gitattributes 일과 LAST_COMMIT 일을 아래와 같이 만든다.
LAST_COMMIT export-subst
$ echo 'Last commit date: $Format:%cd by %aN$' > LAST_COMMIT
$ git add LAST_COMMIT .gitattributes
$ git commit -am 'adding LAST_COMMIT file for archives'
git archive 명령으로 를 만들고 나서 이 일을 열어보면 아래와 같이 보인다.
$ git archive HEAD | tar xCf ../deployment-testing -
$ cat ../deployment-testing/LAST_COMMIT
Last commit date: Tue Apr 21 08:38:48 2009 -0700 by Scott Chacon
이 키드 치환 기으로 커밋 메시지Git 노트, Git Log을 수 있다. 어렵지 않다.
$ echo '$Format:Last commit: %h by %aN at %cd%n%+w(76,6,9)%B$' >
LAST_COMMIT
$ git commit -am 'export-subst uses git log'\''s custom formatter
git archive uses git log'\''s `pretty=format:` processor
directly, and strips the surrounding `$Format:` and `$`
markup from the output.
'
$ git archive @ | tar xfO - LAST_COMMIT
Last commit: 312ccc8 by Jim Hill at Fri May 8 09:14:04 2015 -0700
Ê export-subst uses git log's custom formatter
Ê git archive uses git log's `pretty=format:` processor directly,
and
Ê strips the surrounding `$Format:` and `$` markup from the output.
은 개발할 때가 니라 배포할 때 좋다.
349
Merge 전략
일마다 다른 Merge 을 사용하도록 정할 수 있다. Merge 할 때 일이 있다고 하자. Git
Attrbute로 이 일만 상 타인의 코드 고 내 코드를 사용하도록 정할 수 있다.
정은 다한 환경에서 운영하려고 만든 환경 브랜치를 Merge 할 때 좋다. 이때는 환경 정과 관련일은 Merge
하지 않고 무시하는 게 편하다. 브랜치에 database.xml 이라는 데이터이스 일이 있는데 이 일은
브랜치마다 다. Database 일은 Merge 하면 된다. Attribute아래와 같정하면 이 일은 그냥 두
Merge 한다.
database.xml merge=ours
ours merge 을 다음과 이 정의한다.
$ git config --global merge.ours.driver true
다른 브랜치로 이동해서 Merge를 실했을 때 database.xml 일에 대해 이 발생하는 대신 아래와 같시지를
보게 된다.
$ git merge topic
Auto-merging database.xml
Merge made by recursive.
Merge 했지만 database.xml 일은 원가지고 있던 일 그대로다.
Git Hooks
Git도 다른 버전 관리 시스처럼 어트가 생을 때 자동으로 특정 스크트를 실하도록 할 수 있다.
라이과 서버 으로 나수 있다. 라이은 커이나 Merge 할 때 실되고 서버 Push 할 때
서버에서 실된다. 이 절에서는 어떤 훅이 있고 어떻게 사용하는지 배운다.
훅 설치하기
Git 렉토리 hooks 라는 디렉토리에 저한다. 본 훅 렉토리.git/hooks 이다. 이 디렉토리
가보면 Git이 자동으로 준 매우 유용한 스크트 예제가 개 있다. 고 스크트가 입력이 어인지
에 자세히 있다. 모든 예제는 Perl 스크트로 작성있지만 실할 수만 있으면 되고 Ruby
Python어로 만들어도 된다. 예제 스크트의 일 이름에는 .sample 이라는 확장자가 어 있다.
이름만 바주면 그 을 바로 사용할 수 있다.
할 수 있는 스크일을 확장자 없이 저소의 hooks 렉토리으면 스크트가 . 이 스크트는
350
으로 계속 호출된다. 여기서는 주요 훅 몇 가지에 대해서 명한다.
라이트 훅
라이우 다하다. 이 절에서는 라이committing-workflow , email-workflow 스크,
고 나지로 분해서 명한다.
여기서 한가지 알은 저소를 Clone 해도 라이사되지 않는다는 이다. 만든
정책이 드시 적용되도록 하려면 서버 을 이용해만 하며 작성은 정책 구현하기 부분을 참고한다.
커밋 워크플로 훅
저 커관련을 살펴보자. 관련은 모두 네 가지다.
pre-commit 은 커할 때 가장 먼저 호출되는 으로 커밋 메시지를 작성하기 전에 호출된다. 에서 커하는
Snapshot한다. 것은 없는지, 스트는 실히 했는지 등을 사한다. 할 때 인해할 게 있으면
으로 인한다. 고 이 Exit 코드가 0니면 커소된다. 물론 git commit --no-verify 라고
하면 이 을 일시적으로 생할 수 있다. lint 은 프로그으로 코드 스타일을 사하거나, 라인 백 문자를
사하거나(예제로 들어 있는 pre-commit 이 하는 게 이 일이다), 새로 추가한 코드에 주을 달았는지 사하는 일은
으로 하는 것이 좋다.
prepare-commit-msg Git이 커밋 메시지를 생성하고 나서 편기를 실하기 전에 실된다. 은 사람이
밋 메시지를 수정하기 전에 저 프로그으로 보고 을 때 사용한다. 은 커밋 메시지가 들어 있는 일의 경로,
아규먼트로 는다. 최근 을 수정할 때는(Amending ) SHA-1 을 추가 아규먼트로 더
는다. 사실 이 은 일에는 요 없고 커밋 메시지를 자동으로 생성하는 커에 좋다. 밋 메시지에
릿을 적용하거나, Merge , Squash , Amend 일 때 유용하다. 이 스크트로 커밋 메시지 릿
정보를 입할 수 있다.
commit-msg 은 커밋 메시지가 들어 있는 일의 경로를 아규먼트로 는다. 고 이 스크트가 0닌 값
환하면 커되지 않는다. 에서 적으로 커되기 전에 프로젝트 상나 커밋 메시지를 검증한다.
마지절에서 이 을 사용하는 예제를 보여. 밋 메시지가 정책에 는지 사하는 스크트를 만들어 보자.
되면 post-commit 이 실된다. 은 넘아규먼트가 하나도 없지만 커해시정보는 git log
-1 HEAD 명령으로 쉽게 가져올 수 있다. 적으로 이 스크트는 커된 것을 은 다른 프로그에게 알
사용한다.
이메일 워크플로 훅
크플로에 해당하는 라이은 세 가지이다. 은 모git am 명령으로 실된다. 이 명령어를 사용할
일이 없으면 이 절은 지 않도 된다. 하지만, 가는 git format-patch 명령으로 만든 Patch를 이일로
지도 모른다.
제일 저 실하는 applypatch-msg 이다. 아규먼트는 Author가 보내온 커밋 메시지 일의 이름이다.
이 스크트가 할 때 0닌 값환하면 GitPatch 하지 않는다. 밋 메시지가 규칙는지 인하거나
자동으로 시지를 수정할 때 이 을 사용한다.
git am 으로 Patch 할 때 두 번째로 실되는 pre-applypatch 이다. 아규먼트가 없고 순히 Patch
적용하고 나서 실된다. 서 커할 스냅샷사하는 데 사용한다. 이 스크트로 스트를 수하고 일을 사할
351
수 있다. 스트에 실하거나 가 부하면 0닌 값환시git am 명령을 소시수 있다.
git am 명령에서 마지으로 실되는 post-applypatch . 이 스크트를 이용하면 자동으로 Patch를 보
사람이나 그에게 알시지를 보수 있다. 이 스크트로는 Patch를 중수 없다.
기타 훅
pre-rebase Rebase 하기 전에 실된다. 0닌 값환하면 Rebase소된다. 으로 이
Push 한 커Rebase 하지 못하게 할 수 있다. Git이 자동으로 어주는 pre-rebase 예제가 바로 그 예제다.
예제에는 기준 브랜치가 next 라고 있다. 참고하여 실제로 적용할 브랜치 이름으로 사용하면 된다.
post-rewrite 은 커경하는 명령을 실했을 때 실된다. 예를 들어 git commit --amend 이나 git
rebase 은 명령이 해당한다. git filter-branch 명령은 해당하지 않는다. 아규먼트로 커경하게 한
명령이 전달되고 stdin 으로 경된 커목록이 전달된다. 의 용도는 post-checkout 이나 post-merge
하다고 볼 수 있다.
렉토리에서 가 할 일이 있을 때 사용한다. 그러니까 용이 크거나 Git관리하지 않는 일을 기거나, 문서를
자동으로 생성하는 데 .
post-merge Merge나고 나서 실된다. Git이 추적하지 않는 정보를 관리하는 데
사용한다. MergeWorking Tree경될 때 Git관리하지 않는 일이 원하는 대로 배치됐는지 사할 때도
좋다.
pre-push git push 명령을 실하면 동작하는데 모트 정보를 데이트 하고 난 후 모트로 데이터를
전송하기 전에 동작한다. 모트의 이름과 주소를 터로 전달으며 stdin 데이트 할 해시 스트를
전달는다. Push 하기 전에 커이 유효한지 인하는 용도로 사용할 수 있다. 에서 0닌 값환하면 Push
중지시.
Git은 정상적으로 동작하는 중에도 이따금 git gc --auto 명령으로 가비지 컬렉을 동작시. pre-auto-gc
은 가비지 컬렉이 실되기 전에 호출되는 으로 가비지 컬렉이 동작한다고 사용자에게 알려주거나 지금 시
가비지 컬렉이 동작하기좋지 않다고 Git에 알려주는 용도로 사용할 수 있다.
서버 훅
라이으로도 어정책을 제할 수 있지만, 시스템 관리자에게는 서버 이 더 중요하다. 서버 은 모Push
전후에 실된다. Push 전에 실되는 0닌 값환하면 해당 Push는 거절되고 라이트는 에러 시지를
출력한다. 으로 복잡Push 정책도 가하다.
pre-receive
Push 하면 가처음 실되는 pre-receive 이다. 이 스크트는 표준 입력(STDIN)으로 Push 하는 Refs
목록을 입력는다. 0닌 값환하면 해당 Refs가 전부 거절된다. Fast-forward Push니면 거절하거나,
브랜Push 한을 제어하려면 이 에서 하는 것이 좋다. 관리자만 브랜치를 새로 Push 하고 제할 수 있고 일
개발자는 수정사Push 할 수 있게 할 수 있다.
update
update 스크트는 각 브랜치마다 한 번씩 된다는 것을 제외하면 pre-receive 스크거의 .
브랜치를 여러 개 Push 하면 pre-receive 만 실되지만, update브랜치마다 실된다. 이 스크트는
352
표준 입력으로 데이터를 입력는 것이 니라 아규먼트로 브랜치 이름, 키던 SHA-1 , 사용자가 Push 하는
SHA-1 을 입력는다. update 스크트가 0닌 값환하면 해당 Refs만 거절되고 나지 다른 Refs
없다.
post-receive
post-receive Push 한 후에 실된다. 으로 사용자나 서비스에 알시지를 보수 있다. pre-
receive 처럼 표준 입력(STDIN)으로 Refs 목록이 넘어간다. 으로 스트에 일을 보내거나, CI
(Continuous Integration) 서버나 Ticket-tracking 시스의 정보를 수정할 수 있다. 심지어 커밋 메시지도 할 수
있기 때문에 이 으로 Ticket을 만들고, 수정하고, 을 수 있다. 이 스크트가 전히 할 때까지 라이
연결은 유지되고 Push를 중수 없다. 서 이 스크트로 시간이 오만한 일을 할 때는 심해한다.
책 구현하기
지금까지 배운 것을 한 적용해보자. 나름의 커밋 메시지 규칙으로 사하고 Fast-forward Push 용하고
렉토리마다 사용자의 수정 한을 제어하는 크플로를 만든다. 실질적으로 정책을 제하려면 서버 으로 만들어
한다. 하지만, 개발자들이 Push 할 수 없는 커예 만들지 않도록 라이도 만든다.
스크트는 Ruby 어를 사용한다. 자가 주로 사용하는 어기도 하지만 코드가 접 작성하는 것은
어렵더라도 코드를 고 개념을 이해할 수 있을 것이다. 물론 Git어를 가지 않는다. Git이 자동으로 생성해주는
예제는 모PerlBash로 작성있다. 예제를 열어 보면 PerlBash로 작성된 예제를 참고 할 수 있다.
서버 훅
서버 정책은 전부 update 으로 만든다. 이 스크트는 브랜치가 Push 될 때마다 한 되고 아래 내용을
아규먼트로 는다.
해당 브랜치의 이름
래 브랜치가 가키던 Refs
새로 Push Refs
SSH해서 Push 하는 것이라면 Push 하는 지도 알 수 있다. SSH로 접하지만 개키를 이용하여
개발자 모계정 하나로(“git” ) Push 하고 있다면 실제로 Push 하는 사람이 누구인지 개키를 비하여 판하고
환경수를 정해주는 스크트가 요하다. 아래 스크트에서는 $USER 환경 수에 재 접속한 사용자 정보가
있다고 가정하며 update 스크트는 요한 정보를 수하는 것으로 시작한다.
353
#!/usr/bin/env ruby
$refname = ARGV[0]
$oldrev = ARGV[1]
$newrev = ARGV[2]
$user = ENV['USER']
puts "Enforcing Policies..."
puts "(#{$refname}) (#{$oldrev[0,6]}) (#{$newrev[0,6]})"
스크트에서 전수를 쓰고 있지만 데모의 이해를 기 위해서니 무 나무라지는 마시.
커밋 메시지 규만들기
밋 메시지 규칙부터 해보자. 가 있어하니까 커밋 메시지에 “ref: 1234” 은 스트이 포함있어한다고
가정하자. 은 이커에 있는 이슈와 관련돼 있으니 그 이지 커밋 메시지에 적어 놓으면 좋다. Push
할 때마다 커밋 메시지에 해당 스트이 포함있는지 인한다. 밋 메시지에 해당 스트이 없는 커이면 0
닌 값환해서 Push를 거절한다.
$newrev, $oldrev git rev-list 라는 Plumbing 명령어를 이용해서 Push 하는 모든 커SHA-1
알 수 있다. git log 와 근본적으로 은 명령이고 옵션을 하나도 주지 않으면 다른 정보 없이 SHA-1 만 보여.
명령으로 사이에 있는 커들의 SHA-1 을 살펴보고자 아래와 같은 명령을 사용할 수 있다.
$ git rev-list 538c33..d14fc7
d14fc7c847ab946ec39590d87783c69b031bdfb7
9f585da4401b0a3999e84113824d15245c13f0be
234071a1be950e2a8d078e6141f5cd20c1e61ad3
dfa04c9ef3d5197182f13fb5b9b1fb7717d2222a
17716ec0f1ff5c77eff40b7fe912f9f6cfd0e475
SHA-1 으로 각 커시지도 가온다. 밋 메시지를 가져와서 정규표현 식으로 해당 이 있는지 사한다.
밋 메시지를 방법을 알보자. raw 데이터는 git cat-file 이라는 Plumbing 명령어로 을 수 있다.
Git의 내부 에서 Plumbing 명령어에 대해 자세히 다루니까 지금은 커밋 메시지 는 것에 중하자.
$ git cat-file commit ca82a6
tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
author Scott Chacon <schacon@gmail.com> 1205815931 -0700
committer Scott Chacon <schacon@gmail.com> 1240030591 -0700
changed the version number
이 명령이 출력하는 시지에서 커밋 메시지만 라내한다. 번째 라인 다음부터가 커밋 메시지니까 유스 명령어
sed 라인 이후를 .
354
$ git cat-file commit ca82a6 | sed '1,/^$/d'
changed the version number
이제 커밋 메시지에서 과 일치하는 문자열이 있는지 사해서 있으면 과시키고 없으면 거절한다. 스크트가
할 때 0닌 값환하면 Push가 거절된다. 이 일을 하는 코드는 아래와 같.
$regex = /\[ref: (\d+)\]/
# enforced custom commit message format
def check_message_format
Ê missed_revs = `git rev-list #{$oldrev}..#{$newrev}`.split("\n")
Ê missed_revs.each do |rev|
Ê message = `git cat-file commit #{rev} | sed '1,/^$/d'`
Ê if !$regex.match(message)
Ê puts "[POLICY] Your message is not formatted correctly"
Ê exit 1
Ê end
Ê end
end
check_message_format
이 코드를 update 스크트로 으면 규칙을 어Push 할 수 없다.
ACL로 사용자마다 다른 규적용하기
진행하는 프로젝트에 모이 여러 개라서 모마다 특정 사용자들만 Push 할 수 있게 ACL(Access Control List)
정해한다고 가정하자. 모든 한을 다 가사람들도 있고 특정 디렉토리일만 Push 할 수 있는 사람도 있다.
이런 일을 제하려면 저 서버의 Bare 소에 acl 이라는 일을 만들고 거기에 규칙을 기한다. update
에서 Push 하는 일이 무엇인지 인하고 ACL과 비해서 Push 할 수 있는지 없는지 정한다.
ACL부터 작성한다. CVS에서 사용하는 것과 비ACL을 만든다. 규칙은 한 라인에 하나한다. 각 라인의
번째 필드는 avail 이나 unavail 이고 두 번째 필드는 규칙을 적용할 사용자들의 목록을 CSV(Comma-Separated
Values) 형식으로 적는다. 마지막 필규칙을 적용할 경로를 적는다. 마지막 필드가 비워져 있으면 모든 경로를
한다. 드는 이프(|) 문자로 분한다.
예를 하나 들어보자. 의 모든 한을 가지는 관리자도 여러 명이고 doc 렉토리만 접해서 문서를 만드는
사람도 여러 명이다. 하지만 lib tests 렉토리에 접하는 사람은 한 명이다. 이런 상ACL로 만들면 아래와
.
avail|nickh,pjhyett,defunkt,tpw
avail|usinclair,cdickens,ebronte|doc
avail|schacon|lib
avail|schacon|tests
355
ACL 정보는 스크트에서 어 사용한다. 명을 쉽게 하고자 여기서는 avail 만 처한다. 아래소드는
Associative Array환하는데, 키는 사용자이름이고 은 사용자가 Push 할 수 있는 경로의 목록이다.
def get_acl_access_data(acl_file)
Ê # read in ACL data
Ê acl_file = File.read(acl_file).split("\n").reject { |line| line == '' }
Ê access = {}
Ê acl_file.each do |line|
Ê avail, users, path = line.split('|')
Ê next unless avail == 'avail'
Ê users.split(',').each do |user|
Ê access[user] ||= []
Ê access[user] << path
Ê end
Ê end
Ê access
end
get_acl_access_data 함수가 ACL 일을 환하는 과는 아래와 같.
{"defunkt"=>[nil],
Ê"tpw"=>[nil],
Ê"nickh"=>[nil],
Ê"pjhyett"=>[nil],
Ê"schacon"=>["lib", "tests"],
Ê"cdickens"=>["doc"],
Ê"usinclair"=>["doc"],
Ê"ebronte"=>["doc"]}
게 사용할 한 정보를 만들었다. 이제 Push 하는 일을 그 사용자가 Push 할 수 있는지 없는지 알한다.
git log 명령에 --name-only 옵션을 주면 해당 커에서 수정된 일이 지 알려(git log 명령은 Git
에서 다루었다).
$ git log -1 --name-only --pretty=format:'' 9f585d
README
lib/test.rb
get_acl_access_data 소드를 호출해서 ACL 정보를 하고, 각 커에 들어 있는 일 목록도 은 다음에,
사용자가 모든 커Push 할 수 있는지 판한다.
356
# only allows certain users to modify certain subdirectories in a project
def check_directory_perms
Ê access = get_acl_access_data('acl')
Ê # see if anyone is trying to push something they can't
Ê new_commits = `git rev-list #{$oldrev}..#{$newrev}`.split("\n")
Ê new_commits.each do |rev|
Ê files_modified = `git log -1 --name-only --pretty=format:''
#{rev}`.split("\n")
Ê files_modified.each do |path|
Ê next if path.size == 0
Ê has_file_access = false
Ê access[$user].each do |access_path|
Ê if !access_path # user has access to everything
Ê || (path.start_with? access_path) # access to this path
Ê has_file_access = true
Ê end
Ê end
Ê if !has_file_access
Ê puts "[POLICY] You do not have access to push to #{path}"
Ê exit 1
Ê end
Ê end
Ê end
end
check_directory_perms
git rev-list 명령으로 서버에 Push 하려는 커이 무엇인지 알아낸. 고 각 커에서 수정한 일이 어
것들이 있는지 , 해당 사용자가 모든 일에 대한 한이 있는지 인한다.
이제 사용자는 시지 규칙을 어거나 한이 없는 일이 포함된 커은 어것도 Push 하지 못한다.
새로 작성한 정책 테스트
이 정책을 다 구현해서 update 스크트에 chmod u+x .git/hooks/update 명령으로 실한을 .
린 형식으로 커밋 메시지를 작성하고 Push 하면 아래와 같이 실한다.
357
$ git push -f origin master
Counting objects: 5, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 323 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
Enforcing Policies...
(refs/heads/master) (8338c5) (c5b616)
[POLICY] Your message is not formatted correctly
error: hooks/update exited with error code 1
error: hook declined to update refs/heads/master
To git@gitserver:project.git
Ê! [remote rejected] master -> master (hook declined)
error: failed to push some refs to 'git@gitserver:project.git'
정책과 관련해 하나살펴보자. 이 실될 때마다 아래 메시지가 출력된다.
Enforcing Policies...
(refs/heads/master) (fb8c72) (c56860)
이 내용은 스크부분에서 표준출력(stdout)에 출력한 내용이다. 스크트에서 표준출력으로 출력하면
라이트로 전송된다.
아래의 에러 시지를 살펴보자.
[POLICY] Your message is not formatted correctly
error: hooks/update exited with error code 1
error: hook declined to update refs/heads/master
번째 라인은 스크트에서 접 출력한 것이고 나라인은 Git이 출력해 주는 것이다. 시지는 update
스크트에서 0닌 값환해서 Push 할 수 없다는 시지다. 고 마지막 메시지를 보자.
To git@gitserver:project.git
Ê! [remote rejected] master -> master (hook declined)
error: failed to push some refs to 'git@gitserver:project.git'
시지는 에서 거절된 것이라고 해주는 것이고 브랜치가 거부될 때마다 하나출력된다.
한이 없는 일을 수정해서 Push 해도 에러 시지를 출력한다. 예를 들어 문서 당자가 lib
렉토리에 있는 일을 수정해서 커하면 아래와 같시지가 출력된다.
[POLICY] You do not have access to push to lib/test.rb
358
이제부터는 update 스크트가 상 실되기 때문에 커밋 메시지도 규칙대로 작성해하고, 한이 있는 일만 Push
할 수 있다.
라이트 훅
서버 단점Push 할 때까지 Push 할 수 있는지 없는지 알 수 없다는 데 있다. 들여 정성구현했는데
Push 할 수 없으면 . 히스토리를 제대로 고치는 일은 정신우 해.
이 문제는 라이으로 해한다. 라이으로 서버가 거부할지 사한다. 사람들은 커하기 전에,
그러니까 시간이 지나 고치기 어려지기 전에 문제를 해할 수 있다. Clone 할 때 이 은 전송되지 않기 때문에 다른
방법으로 동에게 배포해한다. 을 가.git/hooks 렉토리사하고 실할 수 있게 만든다.
일을 프로젝트에 어서 배포해도 되고 Git 프로젝트를 만들어서 배포해도 된다. 하지만, 자동으로 치하는 방법
없다.
밋 메시지부터 사해보자. 이 있으면 커밋 메시지가 구리다고 서버가 뒤늦게 거절하지 않는다. 이것은 commit-
msg 으로 구현한다. 은 커밋 메시지가 저일을 번째 아규먼트로 입력는다. 일을
사한다. 요한 이 없으면 커을 중.
#!/usr/bin/env ruby
message_file = ARGV[0]
message = File.read(message_file)
$regex = /\[ref: (\d+)\]/
if !$regex.match(message)
Ê puts "[POLICY] Your message is not formatted correctly"
Ê exit 1
end
이 스크트를 .git/hooks/commit-msg 라는 일로 만들고 실한을 . 시지 규칙을 어기면 아래와
시지를 보여 .
$ git commit -am 'test'
[POLICY] Your message is not formatted correctly
하지 못했다. 하지만, 밋 메지시를 바게 작성하면 커할 수 있다.
$ git commit -am 'test [ref: 132]'
[master e05c914] test [ref: 132]
Ê1 file changed, 1 insertions(+), 0 deletions(-)
한이 없는 일을 수정 못 하게 할 때는 pre-commit 을 이용한다. 사전에 .git 렉토리 안ACL
일을 가다 놓고 아래와 같이 작성한다.
359
#!/usr/bin/env ruby
$user = ENV['USER']
# [ insert acl_access_data method from above ]
# only allows certain users to modify certain subdirectories in a project
def check_directory_perms
Ê access = get_acl_access_data('.git/acl')
Ê files_modified = `git diff-index --cached --name-only HEAD`.split("\n")
Ê files_modified.each do |path|
Ê next if path.size == 0
Ê has_file_access = false
Ê access[$user].each do |access_path|
Ê if !access_path || (path.index(access_path) == 0)
Ê has_file_access = true
Ê end
Ê if !has_file_access
Ê puts "[POLICY] You do not have access to push to #{path}"
Ê exit 1
Ê end
Ê end
end
check_directory_perms
내용은 서버 똑같지만 가지가 다. , 라이Git 렉토리니라 렉토리에서 실하기
때문에 ACL 일 위치가 다. ACL 일 경로를 수정해한다.
access = get_acl_access_data('acl')
이 부분을 아래와 같이 바.
access = get_acl_access_data('.git/acl')
두 번째 차일 목록을 방법이다. 서버 에서는 커에 있는 일을 모두 찾았지만 여기서는 아직 하지도
않았다. Staging Area일 목록을 이용한다.
files_modified = `git log -1 --name-only --pretty=format:'' #{ref}`
이 부분을 아래와 같이 바.
360
files_modified = `git diff-index --cached --name-only HEAD`
가지 만 다고 나지는 똑같. 모트 저소의 계정과 로의 계정도 . 다른 계정을 사용하려면
$user 환경수에 지 알려한다.
을 이용해 Fast-forwardPush는 못 하게 만들 수 있다. Fast-forwardPushRebase로 이
Push 한 커을 바버렸거나 전다른 로컬 브랜치를 Push 하지 못 하도록 하는 것이다.
서버에 이receive.denyDeletes receive.denyNonFastForwards 정을 했다면 더 좁혀.
Push 한 커Rebase 해서 Push 하지 못 하게 만들 때 유용하다.
아래는 이Push 한 커Rebase 하지 못하게 하는 pre-Rebase 스크트다. 이 스크트는 Rebase 할 커
목록을 하고 커모트 Refs/브랜치에 들어 있는지 인한다. 이 한 개라도 모트 Refs/브랜치에 들어 있으면
Rebase 할 수 없다.
#!/usr/bin/env ruby
base_branch = ARGV[0]
if ARGV[1]
Ê topic_branch = ARGV[1]
else
Ê topic_branch = "HEAD"
end
target_shas = `git rev-list #{base_branch}..#{topic_branch}`.split("\n")
remote_refs = `git branch -r`.split("\n").map { |r| r.strip }
target_shas.each do |sha|
Ê remote_refs.each do |remote_ref|
Ê shas_pushed = `git rev-list ^#{sha}^@ refs/remotes/#{remote_ref}`
Ê if shas_pushed.split("\n").include?(sha)
Ê puts "[POLICY] Commit #{sha} has already been pushed to
#{remote_ref}"
Ê exit 1
Ê end
Ê end
end
이 스크트는 비전 회하기 절에서 명하지 않은 표현을 사용했다. 아래표현은 이Push 한 커목록을
어오는 부분이다.
`git rev-list ^#{sha}^@ refs/remotes/#{remote_ref}`
`SHA^@`은 해당 커의 모든 부모를 가. 그러니까 이 명령은 지금 Push 하려는 커에서 모트 저소의
에 도달할 수 있는지 인하는 명령이다. , Fast-forward인지 인하는 것이다.
361
방법우 느고 보요 없다. 차피 Fast-forwardPush-f 옵션을 주어Push 할 수 있다.
문제가 될만한 Rebase지할 수 있다는 것을 보여주려고 이 예제를 명했다.
요약
Git을 프로젝트에 추는 방법을 배. 주요한 서버/라이방법, 위로 정하는 Git Attributes,
, 정책을 제하는 방법을 배. 이제 요한 크플로를 만들고 Git을 거기에 정할 수 있을 것이다.
362
Git과 여타 버전 관리 시스템
세상 일은 대로 되지 않는다. 진행하던 프로젝트를 모Git 소로 기기는 어렵다. Git으로 바
프로젝트가 특정 VCS 시스우 의존적으로 개발 됐을 수도 있다. 부분에서는 기존 VCS 시스
라이트로 Git을 사용하는 방법을 살펴.
가 기존 프로젝트 환경을 Git으로 경하고 게 될 것이다. 부분에서는 프로젝트를 Git으로 경하는
방법에 대해 다. 미리 만들어가 없더라도 스크트를 접 만들어서 기는 방법명한다. 쓰지
않는 VCS를 사용하고 있더라도 Git으로 수 있을 것이다.
Git: Client
Git을 배운 많은 사람들은 만스러한다. 다른 모든 팀원들이 Git 다른 VCS 시스을 사용하고 Git
사용하더라도 만. Git은 이게 다른 VCS 시스연결해 주는 여러 “bridge” 를 제한다. 이어지는 내용을
해 하나둘러보자.
GitSubversion
많은 오픈소스수 많은 기들은 Subversion으로 소스코드를 관리한다. 10여년 이상 Subversion은 가인기있는
오픈소스 VCS 였고 오픈소스 프로젝트에서 선택하는 거의 표준에 가까운 시스이었다. Subversion은 그 이전
시대에서 가많이 사용하던 CVS많이 았다.
Git이 자하는 또 하나의 기git svn 이라는 양방Subversion 지원 도이다. GitSubversion 라이트로
사용할 수 있기 때문에 로에서는 Git의 기을 활용하고 Push 할 때는 Subversion 서버에 Push 한다. 컬 브랜
Merge, Staging Area, Rebase, Cherry-pick 등의 Git 분히 사용할 수 있다. 이 일하는 동
없는 사시대 동에서 일하지만 이다. git svn 은 기에서 git을 사용할 수 있도록 는 출발이다. 회사가 아직
공식적으로 Git을 사용하지 않더라도 동들과 Git을 이용해 더 효율적으로 일할 수 있다. Subversion 지원
는 우DVCS 세상으로 인도하는 은 알.
git svn
GitSubversion을 이어주는 명령은 git svn 으로 시작한다. 이 명령 에 추가하는 명령이 가지 더 있으며 간
예제를 보여주고 명한다.
git svn 명령을 사용할 때는 절름발이인 Subversion을 사용하고 있다는 하자. 가 로컬 브랜
Merge대로 쓸 수 있다고 하더라도 대한 일직선으로 히스토리를 유지하는것이 좋다. Git 소처럼 사용하지
않는다.
히스토리를 재작성해서 Push 하지 말아야 한다. Git을 사용하는 동따로 Git 소에 Push 하지도 말아야 한다.
Subversion순하게 일직선 히스토리만 가하다. 팀원중 일부는 SVN을 사용하고 일부는 Git을 사용하는 팀이라면
SVN Server를 사용해서 협업하는 것이 좋다. 래야 삶이 편해.
363
설정하기
git svn 을 사용하려면 SVN 소가 하나 요하다. 소에 쓰기 한이 있어한다. 쓰기 가한 한 test 소를
사해서 해보자. Subversion에 포함된 svnsync 라는 도를 사용하여 SVN 소를 사한다.
Subversion 소를 하나 만든다.
$ mkdir /tmp/test-svn
$ svnadmin create /tmp/test-svn
고 모든 사용자가 revprops 속성을 경할 수 있도록 0환하는 pre-revprop-change 스크트를
비한다(- 일이 없거나, 다른 이름으로 되어있을 수 있다. 이 경우 아래 내용으로 새로 일을 만들고 실한을
).
$ cat /tmp/test-svn/hooks/pre-revprop-change
#!/bin/sh
exit 0;
$ chmod +x /tmp/test-svn/hooks/pre-revprop-change
이제 svnsync init 명령으로 다른 Subversion 소를 로사할 수 있도록 지정한다.
$ svnsync init file:///tmp/test-svn \
Ê http://your-svn-server.example.org/svn/
게 다른 저소의 주소를 정하면 사할 비가 된다. 아래 명령으로 저소를 실제로 사한다.
$ svnsync sync file:///tmp/test-svn
Committed revision 1.
Copied properties for revision 1.
Transmitting file data .............................[...]
Committed revision 2.
Copied properties for revision 2.
[…]
이 명령은 분 걸지 않는다. 하는 위치가 로니라 모트 서버라면 오. 100개 이하라고
해도 오. Subversion은 한에 커을 하나씩 받아Push 하기 때문에 엄청나게 비효율적이다. 하지만,
소를 사하는 다른 방법은 없다.
시작하기
이제 Subversion 소를 하나 비했다. git svn clone 명령으로 Subversion 소 전Git
소로 가온다. Subversion 소가 로에 있는 것이 니라 모트 서버에 있으면 file:///tmp/test-
svn 부분에 서버 저소의 URL을 적어 .
364
$ git svn clone file:///tmp/test-svn -T trunk -b branches -t tags
Initialized empty Git repository in /private/tmp/progit/test-svn/.git/
r1 = dcbfb5891860124cc2e8cc616cded42624897125 (refs/remotes/origin/trunk)
Ê A m4/acx_pthread.m4
Ê A m4/stl_hash.m4
Ê A java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
Ê A java/src/test/java/com/google/protobuf/WireFormatTest.java
r75 = 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae (refs/remotes/origin/trunk)
Found possible branch point: file:///tmp/test-svn/trunk =>
file:///tmp/test-svn/branches/my-calc-branch, 75
Found branch parent: (refs/remotes/origin/my-calc-branch)
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae
Following parent with do_switch
Successfully followed parent
r76 = 0fb585761df569eaecd8146c71e58d70147460a2 (refs/remotes/origin/my-
calc-branch)
Checked out HEAD:
Ê file:///tmp/test-svn/trunk r75
이 명령은 사실 SVN 소 주소를 주고 git svn init git svn fetch 명령을 순서대로 실한 것과 .
명령은 시간이 좀 걸. Git은 커을 한 에 하나일일이 기록해하는데, 스트용 프로젝트는 커75
정도되서 시간이 오지 않는다. 이 수천개인 프로젝트라면 시간 일이 걸수도 있다.
-T trunk -b branches -t tags 부분은 Subversion이 어떤 브랜구조를 가지고 있는지 Git에게 알려주는
부분이다. Subversion 표준 형식과 다면 이 옵션 부분에서 알은 이름을 지정해. 표준 형식을 사용한다면
하게 -s 옵션을 사용한다. 즉 아래의 명령도 은 의이다.
$ git svn clone file:///tmp/test-svn -s
Git에서 브랜와 태그 정보가 제대로 보이는 지 인한다.
$ git branch -a
* master
Ê remotes/origin/my-calc-branch
Ê remotes/origin/tags/2.0.2
Ê remotes/origin/tags/release-2.0.1
Ê remotes/origin/tags/release-2.0.2
Ê remotes/origin/tags/release-2.0.2rc1
Ê remotes/origin/trunk
Subversion 그를 모트 브랜치처럼 관리하는 것을 알아두한다.
365
Plumbing 명령어인 show-ref 명령으로 모트 브랜치의 정한 이름을 인할 수 있다.
$ git show-ref
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/heads/master
0fb585761df569eaecd8146c71e58d70147460a2 refs/remotes/origin/my-calc-
branch
bfd2d79303166789fc73af4046651a4b35c12f0b refs/remotes/origin/tags/2.0.2
285c2b2e36e467dd4d91c8e3c0c0e1750b3fe8ca refs/remotes/origin/tags/release-
2.0.1
cbda99cb45d9abcb9793db1d4f70ae562a969f1e refs/remotes/origin/tags/release-
2.0.2
a9f074aa89e826d6f9d30808ce5ae3ffe711feda refs/remotes/origin/tags/release-
2.0.2rc1
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/remotes/origin/trunk
Git 서버에서 Clone 하면 모트 브랜치가 니라 그로 관리한다. 적인 Git 소라면 아래와 같.
$ git show-ref
c3dcbe8488c6240392e8a5d7553bbffcb0f94ef0 refs/remotes/origin/master
32ef1d1c7cc8c603ab78416262cc421b80a8c2df refs/remotes/origin/branch-1
75f703a3580a9b81ead89fe1138e6da858c5ba18 refs/remotes/origin/branch-2
23f8588dde934e8f33c263c6d8359b2ae095f863 refs/tags/v0.1.0
7064938bd5e7ef47bfd79a685a62c1e2649e2ce7 refs/tags/v0.2.0
6dcb09b5b57875f334f61aebed695e2e4193db5e refs/tags/v1.0.0
Git 서버로부터 그라면 refs/tags 어서 관리한다.
Subversion 서버에 커밋하기
자 작할 로Git 소는 비했다. 무엇인가 수정하고 Upstream으로 고내용을 Push 할 때가 왔다. Git
Subversion라이트로 사용해서 수정한 내용을 전송한다. 떤 파일을 수정하고 커을 하면 그 수정한 내용은
Git의 로소에 저된다. Subversion 서버에는 아직 반영되지 않는다.
$ git commit -am 'Adding git-svn instructions to the README'
[master 4af61fd] Adding git-svn instructions to the README
Ê1 file changed, 5 insertions(+)
이제 수정한 내용을 UpstreamPush 한다. Git 소에 여러개의 커놓고 한Subversion 서버로
다는 살펴보자. git svn dcommit 명령으로 서버에 Push 한다.
366
$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
Ê M README.txt
Committed r77
Ê M README.txt
r77 = 95e0222ba6399739834380eb10afcd73e0670bc5 (refs/remotes/origin/trunk)
No changes between 4af61fd05045e07598c553167e0f31c84fd6ffe1 and
refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk
이 명령은 새로 추가한 커을 모Subversion에 커하고 로Git 을 다시 만든다. 을 다시 만들기 때문에
된 커SHA-1 이 바뀐다. 모트 Git Subversion 소를 함사용하면 된다.
새로 만들어을 살펴보면 아래와 같git-svn-id 가 추가된다.
$ git log -1
commit 95e0222ba6399739834380eb10afcd73e0670bc5
Author: ben <ben@0b684db3-b064-4277-89d1-21af03df0a68>
Date: Thu Jul 24 03:08:36 2014 +0000
Ê Adding git-svn instructions to the README
Ê git-svn-id: file:///tmp/test-svn/trunk@77 0b684db3-b064-4277-89d1-
21af03df0a68
4af61fd 로 시작하는 SHA-1 이 지금은 95e0222 로 시작한다. Git 서버Subversion 서버에 함
Push 하고 으면 우Subversion 서버에 dcommit 으로 Push를 하고 그 다음에 Git 서버에 Push 한다.
새로변경사항 받아
다른 개발자일하는 과정에서 다른 개발자가 Push 한 상에서 Push를 하면 수 있다. 을 해하지
않으면 서버로 Push 할 수 없다. 이 나면 git svn 명령은 아래와 같이 보여.
367
$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
ERROR from SVN:
Transaction is out of date: File '/trunk/README.txt' is out of date
W: d5837c4b461b7c0e018b49d12398769d2bfc240a and refs/remotes/origin/trunk
differ, using rebase:
:100644 100644 f414c433af0fd6734428cf9d2a9fd8ba00ada145
c80b6127dd04f5fcda218730ddf3a2da4eb39138 M README.txt
Current branch master is up to date.
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.
이런 상에서는 git svn rebase 명령으로 이 문제를 해한다. 이 명령은 경사을 서버에서 내려고 그 다음에
경사을 그 위에 적용한다.
$ git svn rebase
Committing to file:///tmp/test-svn/trunk ...
ERROR from SVN:
Transaction is out of date: File '/trunk/README.txt' is out of date
W: eaa029d99f87c5c822c5c29039d19111ff32ef46 and refs/remotes/origin/trunk
differ, using rebase:
:100644 100644 65536c6e30d263495c17d781962cfff12422693a
b34372b25ccf4945fe5658fa381b075045e7702a M README.txt
First, rewinding head to replay your work on top of it...
Applying: update foo
Using index info to reconstruct a base tree...
M README.txt
Falling back to patching base and 3-way merge...
Auto-merging README.txt
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.
그러면 서버 코드 위에 경사을 적용하기 때문에 성적으로 dcommit 명령을 마수 있다.
368
$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
Ê M README.txt
Committed r85
Ê M README.txt
r85 = 9c29704cc0bbbed7bd58160cfb66cb9191835cd8 (refs/remotes/origin/trunk)
No changes between 5762f56732a958d6cfda681b661d2a239cc53ef5 and
refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk
Push 하기 전에 UpstreamMerge 하는 Git과 달git svn 때만 서버에 데이트할 것이 있다고
알려 (Subversion 처럼). 한다. 다른 사람이 한 일을 수정하고 내가 그 사람과 다른
일을 수정한다면 dcommit 은 성적으로 수된다.
$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
Ê M configure.ac
Committed r87
Ê M autogen.sh
r86 = d8450bab8a77228a644b7dc0e95977ffc61adff7 (refs/remotes/origin/trunk)
Ê M configure.ac
r87 = f3653ea40cb4e26b6281cec102e35dcba1fe17c4 (refs/remotes/origin/trunk)
W: a0253d06732169107aa020390d9fefd2b1d92806 and refs/remotes/origin/trunk
differ, using rebase:
:100755 100755 efa5a59965fbbb5b2b0a12890f1b351bb5493c18
e757b59a9439312d80d5d43bb65d4a7d0389ed6d M autogen.sh
First, rewinding head to replay your work on top of it...
Push 하고 나면 프로젝트 상가 달라다는 을 기한다. 이 없으면 경사이 바대로 적용되지 않
알려주지 않는다. 이 부분이 Git과 다른 이다. Git에서는 서버로 보내기 전에 프로젝트 상를 전부 스트할 수 있다.
SVN은 서버로 커하기 전과 후의 상가 동일하다는 것이 보되지 않는다.
git svn rebase 명령으로도 Subversion 서버의 경사을 가져올 수 있다. 을 보비가 됐어도 .
git svn fetch 명령을 사용해도 되지만 git svn rebase 명령은 경사을 가오고 적용까지 한 에 해.
$ git svn rebase
Ê M autogen.sh
r88 = c9c5f83c64bd755368784b444bc7a0216cc1e17b (refs/remotes/origin/trunk)
First, rewinding head to replay your work on top of it...
Fast-forwarded master to refs/remotes/origin/trunk.
수시로 git svn rebase 명령을 사용하면 로코드를 신 버전으로 유지할 수 있다. 이 명령을 사용하기 전에
렉토리깨끗하게 만드는 것이 좋다. 깨끗하지 못하면 Stash를 하거나 시로 커하고 나서 git svn
rebase 명령을 실하는 것이 좋다. 깨끗하지 않으면 이 나서 Rebase가 중지될 수 있다.
369
Git 브랜치
Git한 사람이면 일을 할 때 토픽 브랜치를 만들고, 일을 다음에, Merge 하는 방식을 쓰려고 할 것이다.
하지만, git svn 으로 Subversion 서버에 Push 할 때는 브랜치를 Merge 하지 않고 Rebase 한다.
Subversion은 일직선 히스토리 에 모GitMerge 도 알지 못한다. git svn 번째 부모 정보만
사용해서 Git Subversion 으로 경한다.
예제를 하나 살펴보자. experiment 브랜치를 하나 만들고 2개의 경사을 커한다. master 브랜치로
Merge 하고 나서 dcommit 명령을 수하면 아래와 같은 모이 된다.
$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
Ê M CHANGES.txt
Committed r89
Ê M CHANGES.txt
r89 = 89d492c884ea7c834353563d5d913c6adf933981 (refs/remotes/origin/trunk)
Ê M COPYING.txt
Ê M INSTALL.txt
Committed r90
Ê M INSTALL.txt
Ê M COPYING.txt
r90 = cb522197870e61467473391799148f6721bcf9a0 (refs/remotes/origin/trunk)
No changes between 71af502c214ba13123992338569f4669877f55fd and
refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk
Merge 이 들어 있는 히스토리에서 dcommit 명령을 실한다. 고 나서 Git 히스토리를 살펴보면 experiment
브랜치의 커은 재작성되지 않았다. 대신 Merge SVN 서버로 전송됐을 뿐이다.
가 이 것을 내려 으면 git merge --squash 한 것 마냥 결과가 합Merge 하나만 볼 수 있다. 다른
사람은 제 어디서 커한 것인지 알 수 없다.
Subversion의 브랜치
Subversion브랜치는 Git브랜달라서 가한 사용을 하지 않는 것이 좋다. 하지만 git svn 으로도
Subversion 브랜치를 관리할 수 있다.
SVN 브랜치 만들기
Subversion 브랜치를 만들려면 git svn branch [new-branch] 명령을 사용한다.
370
$ git svn branch opera
Copying file:///tmp/test-svn/trunk at r90 to file:///tmp/test-
svn/branches/opera...
Found possible branch point: file:///tmp/test-svn/trunk =>
file:///tmp/test-svn/branches/opera, 90
Found branch parent: (refs/remotes/origin/opera)
cb522197870e61467473391799148f6721bcf9a0
Following parent with do_switch
Successfully followed parent
r91 = f1b64a3855d3c8dd84ee0ef10fa89d27f1584302 (refs/remotes/origin/opera)
이 명령은 Subversionsvn copy trunk branches/opera 명령과 동일하다. 이 명령은 브랜치를 Checkout
해주지 않는다는 것을 주의해한다. 여기서 커하면 opera 브랜치가 니라 trunk 브랜치에 커된다.
Subversion 브랜치 넘나들기
dcommit 명령은 어떻게 커브랜치를 정할까? Git은 히스토리에 있는 커중에서 가마지으로 기록된
Subversion 브랜치를 는다. , 현 브랜치 히스토리의 커밋 메시지에 있는 git-svn-id 목을 는 것이기 때문에
브랜치에만 전송할 수 있다.
동시에 여러 브랜치에서 작하려면 Subversion 브랜치에 dcommit 할 수 있는 로컬 브랜치가 요하다. 브랜치는
Subversion 에서 시작하는 브랜치다. 아래와 같opera 브랜치를 만들면 독립적으로 일 할 수 있다.
$ git branch opera remotes/origin/opera
git merge 명령으로 opera 브랜치를 trunk 브랜(master 브랜)Merge 한다. 하지만 -m 옵션을 주고
적절한 커밋 메시지를 작성하지 않으면 에 쓸모없는 "Merge branch opera" 시지가 커된다.
git merge 명령으로 Merge 한다는 것에 주목하자. Git은 자동으로 공통 찾아Merge 에 참고하기 때문에
Subversion에서 하는 것보다 Merge가 더 된다. 여기서 생성되는 Merge 은 일적인 Merge 과 다.
Subversion 서버에 Push 하지만 Subversion에서는 부모가 2개인 커이 있을 수 없다. Push 하면
브랜치에서 만들었던 커여러개가 하나로 합(squash) 것처럼 Push 된다. 서 일Merge 하면 소하거나
해당 브랜치에서 계속 작하기 어렵다. dcommit 명령을 수하면 Merge 브랜치의 정보를 어수 없이 어버
된다. Merge Base을 수 없게 된다. dcommit 명령은 Merge 한 것을 git merge --squash Merge 한 것과
똑 같이 만들어 버. BranchMerge 한 정보는 저되지 않기 때문에 이 문제를 해방법이 없다. 문제를
하려면 trunkMerge 하자마자 해당 브랜치를(여기서는 opera) 제하는 것이 좋다.
Subversion 명령
git svn 명령은 Git으로 전하기 쉽도록 Subversion에 있는 것과 비한 명령어를 지원한다. 마 여기서 명하는
명령은 할 것이다.
SVN 식의 히스토리
Subversion한 사람은 Git 히스토리SVN 형식으로 보고 을 수도 있다. git svn log 명령은 SVN 형식으로
히스토리를 보여.
371
$ git svn log
------------------------------------------------------------------------
r87 | schacon | 2014-05-02 16:07:37 -0700 (Sat, 02 May 2014) | 2 lines
autogen change
------------------------------------------------------------------------
r86 | schacon | 2014-05-02 16:00:21 -0700 (Sat, 02 May 2014) | 2 lines
Merge branch 'experiment'
------------------------------------------------------------------------
r85 | schacon | 2014-05-02 16:00:09 -0700 (Sat, 02 May 2014) | 2 lines
updated the changelog
git svn log 명령에서 기할 것은 가지다. 오프라인에서 동작한다는 이다. SVNsvn log
명령어는 히스토리 데이터를 회할 때 서버가 요하다. 로 이서버로 전송한 커만 출력해. 아직 dcommit
명령으로 서버에 전송하지 않은 로Git 은 보여주지 않는다. Subversion 서버에는 있지만 아직 내려지 않은
경사도 보여주지 않는다. , 재 알고있는 Subversion 서버의 상만 보여.
SVN 노테이션
git svn log 명령이 svn log 명령을 내내는 것처럼 git svn blame [FILE] 명령으로 svn annotate
명령을 수 있다. 과는 아래와 같.
$ git svn blame README.txt
Ê2 temporal Protocol Buffers - Google's data interchange format
Ê2 temporal Copyright 2008 Google Inc.
Ê2 temporal http://code.google.com/apis/protocolbuffers/
Ê2 temporal
22 temporal C++ Installation - Unix
22 temporal =======================
Ê2 temporal
79 schacon Committing in git-svn.
78 schacon
Ê2 temporal To build and install the C++ Protocol Buffer runtime and the
Protocol
Ê2 temporal Buffer compiler (protoc) execute the following:
Ê2 temporal
다시 한번 말하지만 이 명령도 아직 서버로 전송하지 않은 커은 보여주지 않는다.
SVN 서버 정보
svn info 명령은 git svn info 명령으로 대신할 수 있다.
372
$ git svn info
Path: .
URL: https://schacon-test.googlecode.com/svn/trunk
Repository Root: https://schacon-test.googlecode.com/svn
Repository UUID: 4c93b258-373f-11de-be05-5f7a86268029
Revision: 87
Node Kind: directory
Schedule: normal
Last Changed Author: schacon
Last Changed Rev: 87
Last Changed Date: 2009-05-02 16:07:37 -0700 (Sat, 02 May 2009)
blame 이나 log 명령이 오프라인으로 동작하이 이 명령도 오프라인으로 동작한다. 서버에서 가장 최근에 내려
정보를 출력한다.
Subversion에서 무시하는것 무시하기
Subversion 소를 클론하면 쓸데 없는 일을 커하지 않도록 svn:ignore 속성을 .gitignore 일로 만들고
을 것이다. git svn 에는 이 문제와 관련된 명령이 가지 있다. 하나는 git svn create-ignore 명령이다.
해당 위치에 커할 수 있는 .gitignore 일을 생성해.
두 번째 방법git svn show-ignore 명령이다. .gitignore 에 추가할 목록을 출력해 . 프로젝트의 exclude
일로 과를 다이트할 수 있다.
$ git svn show-ignore > .git/info/exclude
게 하면 .gitignore 일로 프로젝트를 더히지 않도 된다. 자서만 Git을 사용하는 거라면 다른 팀원들은
프로젝트에 .gitignore 일이 있는 것을 싫어 할 수 있다.
Git-Svn 요약
git svn 는 여러가지 이유로 Subversion 서버를 사용해만 하는 상에서 을 발한다. 하지만 Git의 모든
장점을 이용할 수는 없다. GitSubversion은 다기 때문에 어질 수도 있다. 이런 문제에 지지 않기 위해서
아래 가이드라인을 지한다.
Git 히스토리를 일직선으로 유지하라. git merge Merge 이 생기지 않도록 하라. Merge Rebase
경사Master 브랜치에 적용하라.
따로 Git 소 서버를 . 클론하기 위해서 잠깐 하나 만들어 쓰는 것은 무하나 절대로 Git 서버에
Push 하지는 말아야 한다. pre-receive 에서 git-svn-id 가 들어 있는 커밋 메시지는 거절하는 방법
괜찮.
이러한 가이드라인을 지키면 Subversion 서버도 쓸만하다. Git 서버를 사용할 수 있으면 Git 서버를 사용하는
것이 훨씬 좋다.
373
GitMercurial
DVCS 세상에 Git만 존재하는 것은 니다. 사실 Git 이외에도 다한 시스이 존재하는데 각자가 나름의 대로 분
버전 관리 시스구현했다. Git 이외에는 Mercurial이 가많이 사용되는 분버전 관리 시스이며 Git
많다.
Mercurial로 코드를 관리하는 프로젝트에서 라이트로 Git을 쓰고자 하는 사람에게도 좋은 소이 있다. Git
Mercurial 라이트로 동작할 수 있다. Mercurial을 위한 Bridge모트 Helper구현돼 있는데 Git모트를
해서 서버 저소의 코드를 가져와서 그. 이 프로젝트의 이름은 git-remote-hg이라고 하며 https://github.com/
felipec/git-remote-hg에 있다.
git-remote-hg
git-remote-hg치한다. 아래처럼 PATH 경로에 포함된 경로중 무데나 git-remote-hg 일을 저하고
한을 .
$ curl -o ~/bin/git-remote-hg \
Ê https://raw.githubusercontent.com/felipec/git-remote-hg/master/git-
remote-hg
$ chmod +x ~/bin/git-remote-hg
예제에서는 ~/bin 렉토리$PATH 경로에 포함되어 있다고 가정한다. git-remote-hg를 실하려면 Python
라이mercurial 요하다. Python치되어있다면 아래처럼 Mercurial 라이치한다.
$ pip install mercurial
(Python 치가 안돼 있다면 https://www.python.org/ 사이트에서 다운로드 받아 설치한다.)
마지으로 Mercurial 라이트도 치해한다. https://www.mercurial-scm.org/ 사이트에서 다운로드 받아
치할 수 있다.
요한 라이리와 프로그치하고 나면 비가 난다. 이제 요한 것은 소스코드를 Push Mercurial
소다. 여기 예제에서는 Mercurial때 많이 쓰는 "hello world" 소를 로제하고 마치 모트
소인 것 처럼 사용한다.
$ hg clone http://selenic.com/repo/hello /tmp/hello
시작하기
이제 Push 할 수 있는 서버”(?) 소가 비됐고 여러가지 작을 해 볼 수 있다. 알려대로 GitMercurial
이나 사용방법은 크게 다지 않다.
Git에서 늘 하던 것처럼 처음에는 Clone저 한다.
374
$ git clone hg::/tmp/hello /tmp/hello-git
$ cd /tmp/hello-git
$ git log --oneline --graph --decorate
* ac7955c (HEAD, origin/master, origin/branches/default, origin/HEAD,
refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master, master)
Create a makefile
* 65bb417 Create a standard "hello, world" program
모트 저소가 hg로 시작하는 Mercurial 소지만 git clone 명령으로 쉽게 Clone 할 수 있다. 사실 내부에서는
git-remote-hg BridgeGit에 포함된 HTTP/S 프로토콜(모트 Helper)과 비하게 동작한다. Git과 마가지로
Mercurial또한 모든 라이트가 전소 히스토리(Clone)해서 사용하도록 만들어기 때문에 Clone
명령으로 히스토리를 포함한 저소 전를 가온다. 예제 프로젝트는 크기가 작서 저소를 금clone 한다.
log 명령으로 커밋 두 개를 볼 수 있으며 가장 최근 으로는 여러 Ref 포인터로 가키고 있다. Ref중 일부는 실제
존재하지 않을 수도 있다. .git 렉토리가 실제로 어떻게 있는지 보자.
$ tree .git/refs
.git/refs
├── heads
ÊÊ └── master
├── hg
ÊÊ └── origin
ÊÊ ├── bookmarks
ÊÊ ÊÊ └── master
ÊÊ └── branches
ÊÊ └── default
├── notes
ÊÊ └── hg
├── remotes
ÊÊ └── origin
ÊÊ └── HEAD
└── tags
9 directories, 5 files
git-remote-hgGit 스타일로 동작하도록 만들어 주는데 속으로 하는 일은 GitMercurial. 모트
Refrefs/hg 렉토리에 저한다. 예를 들어 refs/hg/origin/branches/default Git Ref 일로
내용은 master 브랜치가 가키는 커“ac7955c” 로 시작하는 SHA 해시이다. refs/hg 렉토리는 일
refs/remotes/origin 은 것이지만 마크와 브랜치가 분된다는 이 다.
notes/hg 일은 git-remote-hgGit Mercurial Changeset ID와 매을 하기 위한 시작지이다.
을 들여다보면.
375
$ cat notes/hg
d4c10386...
$ git cat-file -p d4c10386...
tree 1781c96...
author remote-hg <> 1408066400 -0800
committer remote-hg <> 1408066400 -0800
Notes for master
$ git ls-tree 1781c96...
100644 blob ac9117f... 65bb417...
100644 blob 485e178... ac7955c...
$ git cat-file -p ac9117f
0a04b987be5ae354b710cefeba0e2d9de7ad41a9
refs/notes/hg 일은 트하나를 가. 이 트는 다른 객체와 그 이름의 목록인 Git 객체 데이터이스다. git
ls-tree 명령은 이 트리 객체 안에 포함된 모드, 타입, 객체 해시, 일 이름으로 된 여러 목을 보여. 리 객체
포함된 한 목을 더 자세히 살펴보면 “ac9117f으로 시작하는 이름(master 가 가키는 커SHA-1 해시)Blob
객체인할 수 있다. “ac9117f이 가키는 내용은 “0a04b98” 로 시작하는 해시로 default 브랜치가 가키는
Mercurial Changeset ID이다.
이런 내용은 라도 되고 모른다고 정할 요 없다. 적인 크플로에서 Git 모트를 사용하는 것과 크게 다
않다.
다만 한가지, 다음 내용으로 넘어가기 전에 Ignore 일을 살펴보자. MercurialGitIgnore 일은 방식이 거의
하지만 .gitignore 일을 Mercurial 소에 기는 좀 끄럽. 히도 MercurialIgnore
형식Git과 동일해서 아래와 같사하기만 하면 된다.
$ cp .hgignore .git/info/exclude
.git/info/exclude 일은 .gitignore 일처럼 동작하지만 커할 수 없다.
워크플로
이런저런 작을하고 master 브랜치에 커하면 원소에 Push 비가 된다. 재 저소 히스토리를 살펴보면
아래와 같.
376
$ git log --oneline --graph --decorate
* ba04a2a (HEAD, master) Update makefile
* d25d16f Goodbye
* ac7955c (origin/master, origin/branches/default, origin/HEAD,
refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Create a
makefile
* 65bb417 Create a standard "hello, world" program
master 브랜치는 origin/master 브랜치보다 커개를 많으며 이 은 로에만 존재한다. 동시에
가가 커해서 모트 저소에 Push 했다고 가정해보자.
$ git fetch
From hg::/tmp/hello
Ê ac7955c..df85e87 master -> origin/master
Ê ac7955c..df85e87 branches/default -> origin/branches/default
$ git log --oneline --graph --decorate --all
* 7b07969 (refs/notes/hg) Notes for default
* d4c1038 Notes for master
* df85e87 (origin/master, origin/branches/default, origin/HEAD,
refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some
documentation
| * ba04a2a (HEAD, master) Update makefile
| * d25d16f Goodbye
|/
* ac7955c Create a makefile
* 65bb417 Create a standard "hello, world" program
--all 옵션으로 히스토리를 보면 “notes” Ref도 볼 수 있는데 git-remote-hg에서 내부적으로 사용하는 것이
유저는 신경쓰지 않도 된다. 지 내용은 예상한 대로다. origin/master 브랜치에 커하나가 추가되어 있어
히스토리. 에서 살펴보는 다른 버전관리 시스과는 달MercurialMerge분히 다루기
때문에 특히 더 할 일이 없다.
377
$ git merge origin/master
Auto-merging hello.c
Merge made by the 'recursive' strategy.
Êhello.c | 2 +-
Ê1 file changed, 1 insertion(+), 1 deletion(-)
$ git log --oneline --graph --decorate
* 0c64627 (HEAD, master) Merge remote-tracking branch 'origin/master'
|\
| * df85e87 (origin/master, origin/branches/default, origin/HEAD,
refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some
documentation
* | ba04a2a Update makefile
* | d25d16f Goodbye
|/
* ac7955c Create a makefile
* 65bb417 Create a standard "hello, world" program
완벽하고 . Merge 하고 나서 스트가 과한다면 정Push 하고 유할 비가 난 것이다.
$ git push
To hg::/tmp/hello
Ê df85e87..0c64627 master -> master
완벽하게 ! Mercurial 소 히스토리를 살펴보면 기대한대로 모든 것이 지게 난 것을 인할 수 있다.
$ hg log -G --style compact
o 5[tip]:4,2 dc8fa4f932b8 2014-08-14 19:33 -0700 ben
|\ Merge remote-tracking branch 'origin/master'
| |
| o 4 64f27bcefc35 2014-08-14 19:27 -0700 ben
| | Update makefile
| |
| o 3:1 4256fc29598f 2014-08-14 19:27 -0700 ben
| | Goodbye
| |
@ | 2 7db0b4848b3c 2014-08-14 19:30 -0700 ben
|/ Add some documentation
|
o 1 82e55d328c8c 2005-08-26 01:21 -0700 mpm
| Create a makefile
|
o 0 0a04b987be5a 2005-08-26 01:20 -0700 mpm
Ê Create a standard "hello, world" program
Changeset 2 Mercurial로 만든 Changeset이다. 3 4 Changesetgit-remote-hg로 만든
378
Changeset이고 Git으로 Push 한 커이다.
브랜치와 마크
Git 브랜치는 한 뿐이다. Git 브랜치는 새 커이 추가되면 자동으로 마지으로 이동하는 포인터다.
Mercurial에서는 이런 Refs마크라고 부는데 하는 동은 Git브랜와 같.
Mercurial에서 사용하는 브랜의 개념은 Git보다 좀 더 무. MercurialChangeset브랜치도 함한다.
즉 브랜치는 히스토리에 영원히 기록된다. develop 브랜치에 커을 하나 만드는 예제를 살펴보자.
$ hg log -l 1
changeset: 6:8f65e5e02793
branch: develop
tag: tip
user: Ben Straub <ben@straub.cc>
date: Thu Aug 14 20:06:38 2014 -0700
summary: More documentation
“branch” 로 시작하는 라인이 있는 것을 볼 수 있다. Git은 이런 방식(요도) 없다(Gitref
표현할 수는 있). 하지만 Mercurial요로 하는 정보이기에 git-remote-hg는 이런 비한 정보가 요하다.
Mercurial 마크를 만드는 것은 Git브랜치를 만드는 것과 이 쉽다. Git으로 Clone Mercurial 소에 아래와
브랜치를 Push 한다.
$ git checkout -b featureA
Switched to a new branch 'featureA'
$ git push origin featureA
To hg::/tmp/hello
Ê* [new branch] featureA -> featureA
게만 해도 마크가 생성된다. Mercurial로 저소 내용을 인하면 아래와 같.
379
$ hg bookmarks
Ê featureA 5:bd5ac26f11f9
$ hg log --style compact -G
@ 6[tip] 8f65e5e02793 2014-08-14 20:06 -0700 ben
| More documentation
|
o 5[featureA]:4,2 bd5ac26f11f9 2014-08-14 20:02 -0700 ben
|\ Merge remote-tracking branch 'origin/master'
| |
| o 4 0434aaa6b91f 2014-08-14 20:01 -0700 ben
| | update makefile
| |
| o 3:1 318914536c86 2014-08-14 20:00 -0700 ben
| | goodbye
| |
o | 2 f098c7f45c4f 2014-08-14 20:01 -0700 ben
|/ Add some documentation
|
o 1 82e55d328c8c 2005-08-26 01:21 -0700 mpm
| Create a makefile
|
o 0 0a04b987be5a 2005-08-26 01:20 -0700 mpm
Ê Create a standard "hello, world" program
[featureA] 그가 비전 5에 생것을 볼 수 있다. Git라이트로 사용하는 저소에서는 Git 브랜치처럼
사용한다. Git 라이트 저소에서 한 가지 할 수 없는 것은 서버의 마크를 제하지 못 한다(이는 모트 Helper
이다).
Git보다 무거운 Mercurial 브랜치도 물론 사용 가하다. 브랜치 이름에 branches 네임이스를 사용하면 된다.
$ git checkout -b branches/permanent
Switched to a new branch 'branches/permanent'
$ vi Makefile
$ git commit -am 'A permanent change'
$ git push origin branches/permanent
To hg::/tmp/hello
Ê* [new branch] branches/permanent -> branches/permanent
위의 내용을 Mercurial에서 인하면 아래와 같.
380
$ hg branches
permanent 7:a4529d07aad4
develop 6:8f65e5e02793
default 5:bd5ac26f11f9 (inactive)
$ hg log -G
o changeset: 7:a4529d07aad4
| branch: permanent
| tag: tip
| parent: 5:bd5ac26f11f9
| user: Ben Straub <ben@straub.cc>
| date: Thu Aug 14 20:21:09 2014 -0700
| summary: A permanent change
|
| @ changeset: 6:8f65e5e02793
|/ branch: develop
| user: Ben Straub <ben@straub.cc>
| date: Thu Aug 14 20:06:38 2014 -0700
| summary: More documentation
|
o changeset: 5:bd5ac26f11f9
|\ bookmark: featureA
| | parent: 4:0434aaa6b91f
| | parent: 2:f098c7f45c4f
| | user: Ben Straub <ben@straub.cc>
| | date: Thu Aug 14 20:02:21 2014 -0700
| | summary: Merge remote-tracking branch 'origin/master'
[...]
“permanent” 라는 브랜치가 Changeset 7 에 기록됐다.
Mercurial 소를 Clone Git 소에서는 Git 브랜치를 쓰Checkout, Checkout, Fetch, Merge, Pull 명령을
그대로 쓰면 된다. 드시 기할 게 하나 있는데 Mercurial은 히스토리를 재작성을 지원하지 않고 순히 추가된다.
Git으로 Rebase를 하고 제로 Push 하면 Mercurial 소의 모습은 아래와 같아진.
381
$ hg log --style compact -G
o 10[tip] 99611176cbc9 2014-08-14 20:21 -0700 ben
| A permanent change
|
o 9 f23e12f939c3 2014-08-14 20:01 -0700 ben
| Add some documentation
|
o 8:1 c16971d33922 2014-08-14 20:00 -0700 ben
| goodbye
|
| o 7:5 a4529d07aad4 2014-08-14 20:21 -0700 ben
| | A permanent change
| |
| | @ 6 8f65e5e02793 2014-08-14 20:06 -0700 ben
| |/ More documentation
| |
| o 5[featureA]:4,2 bd5ac26f11f9 2014-08-14 20:02 -0700 ben
| |\ Merge remote-tracking branch 'origin/master'
| | |
| | o 4 0434aaa6b91f 2014-08-14 20:01 -0700 ben
| | | update makefile
| | |
+---o 3:1 318914536c86 2014-08-14 20:00 -0700 ben
| | goodbye
| |
| o 2 f098c7f45c4f 2014-08-14 20:01 -0700 ben
|/ Add some documentation
|
o 1 82e55d328c8c 2005-08-26 01:21 -0700 mpm
| Create a makefile
|
o 0 0a04b987be5a 2005-08-26 01:20 -0700 mpm
Ê Create a standard "hello, world" program
Changeset 8, 9, 10 이 생성됐고 permanent 브랜치에 속한다. 하지만 예전에 Push 했던 Changeset들이 그대로
남아있다. 그러면 Mercurial 소를 유하는 동들은 . 으로 커을 재작성 하고 제로 Push 하지
지어다.
Mercurial 요약
GitMercurial은 시스이 크게 다지 않서 쉽게 경계를 넘나들 수 있다. 미 리모트로 나 보
재작성하지 않는다면(물론 Git도 마가지) 지금 작하고 있는 저소가 Git인지 Mercurial인지 라도 된다.
GitBazaar
DCVS 중에 다른 유명한 것으로 Bazaar 라는 것이 있다. Bazaar는 무이고 오픈소스로 GNU 프로젝트 중 하나이다.
Git과 동작방식우 다. Git과 동일한 동작을 하기 위해 우 다를 키드를 사용하기도 하며, 은 키드가 전
다른 의로 쓰이기도 한다. 특히 브랜관리에 대한 개념이 우 달라 Git을 쓰던 사람에게는 기도 하다.
382
그럼에도 불구하고 Git 라이트를 사용하여 Bazaar의 저소를 기으로 버전관리 을 할 수 있다.
여러분이 GitBazaar 라이트로 사용하도록 기을 제해주는 수 많은 프로젝트가 있다. 이 책에서는 Felipe
Contreras의 프로젝트를 가다 사용하며 https://github.com/felipec/git-remote-bzr 에서 할 수 있다.
프로젝트에서 git-remote-bzr 일을 받아 `$PATH`에 지정된 디렉토리 중 하나에 위치시면 바로 사용할 수 있다.
$ wget https://raw.github.com/felipec/git-remote-bzr/master/git-remote-bzr
-O ~/bin/git-remote-bzr
$ chmod +x ~/bin/git-remote-bzr
물론 Bazaar치되어 있어한다. 이로서 비 작이다.
Bazaar 저장소로부터 Git 저장소 생성
Bazaar 소를 로Clone 하기는 쉽다. 소 주소 bzr:: 문자열을 여서 Clone 하면 된다. GitBazaar
소 전를 로제하여 사용하기 때문에 로에 이내려Bazaar 소를 Clone 수도 있지만
하지는 않는다. Bazaar 소가 가키고 있는 원모트 저소로부터 Clone 하는 것이 여러모로
하다.
모트 저소의 주소가 다음과 ssh를 사용하는 경우
bzr+ssh://developer@mybazaarserver:myproject Clone 할 때의 주소는 다음과 .
$ git clone bzr::bzr+ssh://developer@mybazaarserver:myproject myProject-
Git
$ cd myProject-Git
Clone을 하고 나면 Git 소가 생성되었지만 디스크 사용에 있어서 된 상니다. 소 크기가 제법 큰
경우 다음 명령으로 Git 소의 디스크 사용을 수 있다.
$ git gc --aggressive
Bazaar 브랜치
Bazaar의 경우 저소에는 많은 브랜치가 있더라도 Clone 할 때는 브랜치 하나만을 Clone 할 수 있다. 하지만 git-
remote-bzr 명령은 가지 방식 다 사용 가하다. 예를 들어 브랜치 하나만 Clone 하려면:
$ git clone bzr::bzr://bzr.savannah.gnu.org/emacs/trunk emacs-trunk
소 전Clone 하려면:
$ git clone bzr::bzr://bzr.savannah.gnu.org/emacs emacs
두 번째 명령을 실하면 emacs 소의 모든 브랜치를 Clone 하게 된다. 일부 브랜치만 Clone 하거나 사용하도록
383
다음과 정할 수도 있다.
$ git config remote-bzr.branches 'trunk, xwindow'
떤 리모트 저소의 경우 브랜치의 목록을 보여주지 않을수도 있지만 아래와 같접 지정해다면 어렵지 않게
지정된 브랜치를 포함하는 저위로 Clone 할 수 있다.
$ git init emacs
$ git remote add origin bzr::bzr://bzr.savannah.gnu.org/emacs
$ git config remote-bzr.branches 'trunk, xwindow'
$ git fetch
.bzrignore로 무시하는 파일 Git에서도 무시하기
Bazaar관리하는 저소에서 작하는 경우 .gitignore 일을 운영하지 말아야 한다. 일이 생성되어
버전관리에 추가된다면 Bazaar를 사용하는 다른 동해하는 이다. 이를 해하기 위해 .git/info/exclude
일에 내용을 입력하거나 크로 생성하는 방법이 있다. 자세한 내용은 이어지는 부분에서 인할 수 있다.
Bazaar일 무시하기 기Git의 무시하기 기방식으로 동작한다. 하지만 정은 것은 니며 가지
Git과 다게 동작한다. 한 전내용은 ignore 도움 에서 인할 수 있다. 가지 다른은 다음과 .
1. "!!" 문자열로 시작하는 은 이"!" 문자열로 시작하는 정의한 제로 다시 적용시키는 규칙이다.
(무시하지 않는 것을 다시 무시하기!)
2. "RE:" 문자열로 시작하는 규칙Python 규표현식 을 적용한다. GitGlob 만 적용 가하다.
이러한 Bazaar 일 무시하기 규칙Git 관리에도 적용하려면:
1. .bzrignore 일이 위의 가지 Git과 다른 규칙을 사용하지 않고 있다면 간히 심볼릭 링크를 만들어 Git
소에도 적용할 수 있다: ln -s .bzrignore .git/info/exclude
2. 대의 경우 .git/info/exclude 일을 일반 파일로 생성하거나 수정해서 .bzrignore 일과 은 의
적용되도록 접 수정해한다.
경우에도 .git/info/exclude 일이 .bzrignore 일이 에 따라 적절하게 내용을 영하고 있는지
주의를 기여 살펴한다. "!!" 이나 "RE:" 규칙이 새로이 .bzrignore 일에 적용된 경이 있을 수
있다. Git이 적절히 처할 수 없는 이 새로이 생난 경우 .git/info/exclude 일을 일반파일로
작성하고 의 내용을 이해한 다음 적절히 환하여 Git 으로 작성해한다. .git/info/exclude 일은
심볼릭 링크였으로 일이를 지우는 것 부터 드시 실한다. 그 이후 .bzrignore 일을
.git/info/exclude 일로 사하고 Git이 이해하지 못하는 에 대해 경 작을 해한다. "!!" 의 경우
Git에는 적용이 하기 때문에 주의해서 이를 환해한다.
리모트 저장소로부터 변경 내용 가져오
소로부터 경 내용을 가오려면 보Git 명령을 사용하Pull 명령을 사용한다. 경 내용이
master 브랜치에 있다면 origin/master 브랜치를 Merge 하거나 다음과 Rebase 하게 된다.
384
$ git pull --rebase origin
리모트 저장소로 변경 내용 보내기
Bazaar에도 Merge 에 대한 개념이 동일하게 있기 때문에 Merge Push 하는 것은 무런 문제가 없다.
브랜치에서 작을 하다가 master 브랜치로 Merge 하고 이를 Push 하는 것 물론 하다. 접 생성한 브랜치를 Push
할 수도 있다. 브랜치를 만들고 스트을 만들고 Bazaar 소로 Push 하면 된다.
$ git push origin master
주의
Git모트-레임워크의 제가지 적용된다. 특히 아래의 명령을 적용하기 하다.
git push origin :branch-to-delete (Bazaar 에서는 이런으로 Ref 또는 브랜제가 )
git push origin old:new ('old' 브랜치를 Push 하게 )
git push --dry-run origin branch (실제로 Push 하게 )
요약
GitBazaar의 버전관리 있기 때문에 둘의 경계를 넘나드는 작은 그어려운 것은 니다. 하지만
무런 제이 없는 것은 니기 때문에 GitClient로 사용할 때 상 원소가 Bazaar 을 생각해
사용한다면 무는 없을 것이다.
GitPerforce
Perforce는 기에서 많이 사용하는 버전 관리 시스이다. 1995년 무렵부터 사용됐으며 이 에서 다루는 시스중에서
된 버전 관리 시스이다. 처음 Perforce를 만든 당시 환경에 계했기 때문에 가지 특이 있다. 제나
서버에 연결할 수 있고 로에는 한 버전만 저한다. Perforce잘 맞크플로도 있지만 Git을 도입하면 훨씬
나은 크플로를 적용할 수 있을 것이라 생각한다.
PerforceGit을 함사용하는 방법가지다. 번째Perforce가 제하는 “Git Fusion이다. Perforce
Depot의 서고 쓸 수 있는 Git 소로 노출 시. 두 번째 방법git-p4라는 라이Bridge
사용하여 GitPerforce라이트로 사용하는 것이다. 방법Perforce 서버를 지 않도 된다.
Git Fusion
PerforceGit Fusion(http://www.perforce.com/git-fusion 에서 다운로드 을 수 있음)이라는 제을 제한다.
이 제Perforce 서버서버에 있는 Git 소를 동기한다.
385
Git Fusion 설치
Perforce Git Fusion이 포함된 가상 신 이지를 내려는 것이 Git Fusion을 가쉽게 치하는 방법이다.
가상신 이지는 http://www.perforce.com/downloads/Perforce/20-User Git Fusion 에서 을 수
있다. VirtualBox 은 가상소프트어로 이 이지를 동작시수 있다.
가상신을 처음 부팅시키면 root, perforce, git Linux 계정의 호를 입력하라는 면과 가상신 인스
이름을 입력하라는 면이 나타난다. 인스스 이름은 에서 인스스를 분하고 접하기 위해
사용하는 이름이다. 이러한 과정을 마치고 나면 아래와 같면을 볼 수 있다.
그림 146. Git Fusion 가상머신 부화면.
면의 IP 주소는 계속 사용할 거라서 기한다. 다음은 Perforce 사용자를 생성해보자. “Login” 목으로
이동해서 터키를 누르(또는 SSH로 접속하면) root 로 로그인한다. 아래 명령으로 Perforce 사용자를
생성한다.
386
$ p4 -p localhost:1666 -u super user -f john
$ p4 -p localhost:1666 -u john passwd
$ exit
번째 명령을 실하면 VI 기가 고 생성한 사용자의 정보를 수정할 수 있다. 으로 입력되어있는 정보를 그대로
사용하려면 간:wq 를 키보드로 입력하고 터키를 른다. 두 번째 명령을 실하면 생성한 Perforce 사용자의
호를 는데 전하게 두 번 는다. 에서 하는 작은 여기까지이에서 나온다.
다음으로 해할 작라이트 환경에서 GitSSL 서를 검증하지 않도록 정하는 것이다. Git Fusion
지에 포함된 SSL 서는 도인 이름으로 접속을 검증한다. 여기서는 IP 주소로 접할 거라서 GitHTTPS
서를 검증하지 못한다. 서 접속할 수도 없다. Git Fusion 가상신 이지를 실제로 사용할 거라면 Perforce
Git Fusion 뉴얼을 참고해서 SSL 서를 새로 치해서 사용하는 것을 한다. 해보는 거라면 인검증
하면 된다.
$ export GIT_SSL_NO_VERIFY=true
제대로 작동하는지 아래 명령으로 인해보자.
$ git clone https://10.0.1.254/Talkhouse
Cloning into 'Talkhouse'...
Username for 'https://10.0.1.254': john
Password for 'https://john@10.0.1.254':
remote: Counting objects: 630, done.
remote: Compressing objects: 100% (581/581), done.
remote: Total 630 (delta 172), reused 0 (delta 0)
Receiving objects: 100% (630/630), 1.22 MiB | 0 bytes/s, done.
Resolving deltas: 100% (172/172), done.
Checking connectivity... done.
Perforce가 제한 가상신 이지는 플 프로젝트가 하나 들어 있다. HTTPS 프로토콜로 프로젝트를 Clone
Git은 인정보를 는다. 서 만든 john 이라는 사용자이름과 호를 입력한다. Credential 시로 사용자이름과
호를 저면 이 계를 .
Git Fusion 설정
Git Fusion치하고 나서 정을 경할 수 있다. 미 잘 쓰고 있는 Perforce 라이트가 있으면 그걸로 경할 수
있다. Perforce 서버의 //.git-fusion 렉토리에 있는 일을 수정하면 된다. 렉토리 구조아래와 같.
387
$ tree
.
├── objects
ÊÊ ├── repos
ÊÊ ÊÊ └── [...]
ÊÊ └── trees
ÊÊ └── [...]
├── p4gf_config
├── repos
ÊÊ └── Talkhouse
ÊÊ └── p4gf_config
└── users
Ê └── p4gf_usermap
498 directories, 287 files
objects 렉토리Git FusionPerforce 객체와 Git양방으로 대시키는 내용을 고 있으로 이 디렉토리
의 내용을 의로 수정하지 말아야 한다. p4gf_config 일은 루트 디렉토리, 고 각 저소마다 하나있으며
Git Fusion이 어떻게 동작하는지를 정하는 일이다. 루트 디렉토리의 이 일 내용을 보면 아래와 같.
388
[repo-creation]
charset = utf8
[git-to-perforce]
change-owner = author
enable-git-branch-creation = yes
enable-swarm-reviews = yes
enable-git-merge-commits = yes
enable-git-submodules = yes
preflight-commit = none
ignore-author-permissions = no
read-permission-check = none
git-merge-avoidance-after-change-num = 12107
[perforce-to-git]
http-url = none
ssh-url = none
[@features]
imports = False
chunked-push = False
matrix2 = False
parallel-push = False
[authentication]
email-case-sensitivity = no
이 책에서는 이 일 내용 한 그 의명하지는 않는다. Git에서 사용하는 환경일과 마가지로 INI
형식으로 관리된다는 을 알아두면 된다. 루트 디렉토리에 위치한 이 일은 전정이다.
repos/Talkhouse/p4gf_config 처럼 각 저소마다 정할 수도 있는데 전정 위에(Override) 적용된다.
별 설일의 내용을 보면 아래와 같이 전정과 다른 섹션이 있다.
[Talkhouse-master]
git-branch-name = master
view = //depot/Talkhouse/main-dev/... ...
일 내용을 보면 PerforceGit브랜치간 정보를 볼 수 있다. 섹션 이름은 치지만 않으면 무거나 사용할 수
있다. git-branch-name 목은 고 입력하기 어려운 Depot 경로를 Git에서 사용하기에 편한 이름으로 연결.
view 목은 어떻게 Perforce 일이 Git 소에 되는지를 View 을 사용하여 정한다. 여러 목을
정할 수 있다.
389
[multi-project-mapping]
git-branch-name = master
view = //depot/project1/main/... project1/...
Ê //depot/project2/mainline/... project2/...
와 같으로 성하면 디렉토리 안경사Git 소로 영된다.
마지으로 살펴볼 일은 users/p4gf_usermap 일로 Perforce 사용자를 Git 사용자로 하는 할을
하는데 때에 따라서는 요하지 않을 수도 있다. Perforce ChangesetGit의 커으로 환할 때 Git Fusion
Perforce 사용자의 이름과 이일 주소를 가지고 Git 의 저자터 정보를 입력한다. 대로 Git Perforce
Changeset으로 환할 때는 Git 에 저된 이름과 이일 정보를 가져와 Changeset에 기록하고 이 정보로 한을
인한다. 모트 저소에 동일한 정보가 등록 있어서 문제없지만 정보가 다다면 아래와 같정보를
정해한다.
john john@example.com "John Doe"
john johnny@appleseed.net "John Doe"
bob employeeX@example.com "Anon X. Mouse"
joe employeeY@example.com "Anon Y. Mouse"
정은 한 라인에 한 유저씩 설정하며 ID "< 이름>" 형식으로 성한다. 번째 라인과 두 번째 라인은
일 주소 개를 Perforce 유저 하나로 한다. 정하면 Git 에 이일 주소를 여러 개 사용했어도 한
Perforce 유저의 Changeset으로 환할 수 있다. 대로 Perforce ChagesetGit 으로 경할 때는 번째
정보를 이용하여 커의 저자 정보를 기록한다.
마지막 두 라인은 Perforce 사용자 bobjoeGit 으로 환할 때는 은 이름을 쓰도록 정한 것이다. 이는 내부
프로젝트를 오픈 소스로 개할 때, 내부 개발자 이름을 드러내지 않고 외부로 오픈할 때 유용하다. Git 을 한 사람이
작성한 것으로 하려는게 니라면 사람 이름과 이일 주소는 중되지 않아야 한다.
워크플로
PerforceGit FusionGitPerforce사이에서 양방의 데이터 환을 지원하는 Bridge이다. GitPerforce
라이트로 사용할 때 어떤식으로 사용하면 되는지 예제를 해 살펴보자. 위에서 살펴본 설일로 “Jam” 이라는
Perforce 프로젝트를 아래와 같Clone 할 수 있다.
390
$ git clone https://10.0.1.254/Jam
Cloning into 'Jam'...
Username for 'https://10.0.1.254': john
Password for 'https://john@10.0.1.254':
remote: Counting objects: 2070, done.
remote: Compressing objects: 100% (1704/1704), done.
Receiving objects: 100% (2070/2070), 1.21 MiB | 0 bytes/s, done.
remote: Total 2070 (delta 1242), reused 0 (delta 0)
Resolving deltas: 100% (1242/1242), done.
Checking connectivity... done.
$ git branch -a
* master
Ê remotes/origin/HEAD -> origin/master
Ê remotes/origin/master
Ê remotes/origin/rel2.1
$ git log --oneline --decorate --graph --all
* 0a38c33 (origin/rel2.1) Create Jam 2.1 release branch.
| * d254865 (HEAD, origin/master, origin/HEAD, master) Upgrade to latest
metrowerks on Beos -- the Intel one.
| * bd2f54a Put in fix for jam's NT handle leak.
| * c0f29e7 Fix URL in a jam doc
| * cc644ac Radstone's lynx port.
[...]
저 처음 저소를 Clone 할 때는 시간이 우 많이 걸수 있다. Git FusionPerforce 소에서 가온 모든
ChangesetGit 으로 환하기 때문이다. 환하는 과정이야 빠르더라도 히스토리 크기가 크다면 전Clone
하는 시간은 오기 마이다. 게 한 Clone 한 후에 추가된 내용만을 받아오는 시간은 Git
가지로 오지 않는다.
Clone 한 저소는 지금까지 살펴적인 Git 와 똑같. 인해보면 브랜치가 3개 있다. Git은 로
master 브랜치가 서버의 origin/master 브랜치를 추적하도록 미리 만들어 . 내키는대로 일을 좀 수정하고
하면 아래와 같이 히스토리인 모습을 볼 수 있다.
# ...
$ git log --oneline --decorate --graph --all
* cfd46ab (HEAD, master) Add documentation for new feature
* a730d77 Whitespace
* d254865 (origin/master, origin/HEAD) Upgrade to latest metrowerks on
Beos -- the Intel one.
* bd2f54a Put in fix for jam's NT handle leak.
[...]
새 커밋 두 개가 로히스토리였다. 다른 사람이 Push 한 일이 있는지 인해보자.
391
$ git fetch
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://10.0.1.254/Jam
Ê d254865..6afeb15 master -> origin/master
$ git log --oneline --decorate --graph --all
* 6afeb15 (origin/master, origin/HEAD) Update copyright
| * cfd46ab (HEAD, master) Add documentation for new feature
| * a730d77 Whitespace
|/
* d254865 Upgrade to latest metrowerks on Beos -- the Intel one.
* bd2f54a Put in fix for jam's NT handle leak.
[...]
그새 가 부지런히 일을 했나보다. 가 어일을 했는지는 커을 까지만 어Git Fusion
서버로부터 새로 가Changeset환해서 6afeb15 을 만들어. Git에서 여타 커
않다. 이제 Perforce 서버가 Merge 을 어떻게 다루는지 살펴보자.
$ git merge origin/master
Auto-merging README
Merge made by the 'recursive' strategy.
ÊREADME | 2 +-
Ê1 file changed, 1 insertion(+), 1 deletion(-)
$ git push
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 917 bytes | 0 bytes/s, done.
Total 9 (delta 6), reused 0 (delta 0)
remote: Perforce: 100% (3/3) Loading commit tree into memory...
remote: Perforce: 100% (5/5) Finding child commits...
remote: Perforce: Running git fast-export...
remote: Perforce: 100% (3/3) Checking commits...
remote: Processing will continue even if connection is closed.
remote: Perforce: 100% (3/3) Copying changelists...
remote: Perforce: Submitting new Git commit objects to Perforce: 4
To https://10.0.1.254/Jam
Ê 6afeb15..89cba2b master -> master
Git은 이Merge 하고 Push 하면 되었거니 한다. Perforce관점에서 README 일의 히스토리를 생각해보자.
Perforce 히스토리p4v 프 기으로 볼 수 있다.
392
그림 147. GitPush Perforce 리비전 결과 그래프.
Perforce의 이런 히스토리 어를 적이 없다면 다소 지만 Git 히스토리를 보는 것과 크게 다지 않다.
README 일의 히스토리를 보는 상이다. 왼쪽 에서 README 일과 관련브랜렉토리
나타난다. 오른에서는 일의 비전 히스토리 프를 볼 수 있다. 오른아래 창에서는 이 그프의
인할 수 있다. 왼쪽 아래 창에는 선택비전을 자세히 보여(이 그에서는 비전 `2`)
Perforce의 히스토리 프상으로는 Git의 히스토리와 똑 같아 보인다. 하지만, Perforce1 2 을 저할 만한
브랜치가 없다. .git-fusion 렉토리 안브랜치를 만든다. Git 브랜치가 Perforce브랜
치되지 않은 경우에도 이와 같은 모이 된다(브랜치간 은 나중에 정할 수도 있다).
이런 작들은 Git Fusion 내부에서 보이지 않게 처된다. 물론 과로 Git 라이트로 Perforce 서버에 접하는
사람이 있다는 것을 가는 알게 된다.
Git-Fusion 요약
Perforce 서버에 한이 있다면 Git FusionGitPerforce 서버간에 데이터를 주고는 도우 유용하다. 물론
정해하는 부분도 있지만 히는게 그어렵지는 않다. 이 절에서는 Git심해서 사용하라고 하지 않는다.
절은 그런 절이다. 다고 Perforce 서버가 무거나 다 받아 주지 않는다. Push 한 히스토리를 재작성하고 Push
하면 Git Fusion이 거절한다. 이런 경우에도 Git Fusion은 열심히 노력해서 Perforce를 마치 Git 처럼 다수 있게
와준. (Perforce 사용자에게는 생소하지만) Git 도 사용할 수 있고 브랜(Perforce 에는
Integration으로 기록된다)Merge 할 수도 있다.
서버 관리 한이 없으면 Git Fusion을 쓸 수 없지만 아직 다른 방법남아 있다.
Git-p4
393
Git-p4GitPerforce간의 양방Bridge이다. Git-p4는 모든 작라이트인 Git 에서 이루어지기
때문에 Perforce 서버에 대한 한이 없어도 된다. 물론, 정보 정도는 Perforce 서버가 요하다. Git-p4Git
Fusion만큼 성도 고 유하지 않지만 Perforce 서버를 지 않고서도 대부분은 다 할 수 있게 해.
git-p4동작하려면 p4 명령을 어디에서나 사용할 수 있게 PATH 에 등록해한다. `p4`
http://www.perforce.com/downloads/Perforce/20-User 에서 다운로드 을 수 있다.
설정
예제로 사용할 Perforce 프로젝트를 가오기 위해 에서 살펴Git Fusion OVA 지의 Perforce 서버를 사용한다.
Git Fusion 서버 정은 Perforce 서버정 부분만 정하면 된다.
git-p4이 의존하는 p4 라이트를 커드라인에서 사용하기 위해 가지 환경수를 정해한다.
$ export P4PORT=10.0.1.254:1666
$ export P4USER=john
시작하기
Git에서 모든 시작은 Clone 이다. Clone저 한다.
$ git p4 clone //depot/www/live www-shallow
Importing from //depot/www/live into www-shallow
Initialized empty Git repository in /private/tmp/www-shallow/.git/
Doing initial import of //depot/www/live/ from revision #head into
refs/remotes/p4/master
Git어로 표현하자면 위의 명령은 “shallow” Clone을 한다. 모든 저소의 히스토리를 가오지 않고 마지
비전의 히스토리만 가온다. 을 기한다. Perforce는 저소의 모든 히스토리를 모든 사용자에게 용하지
않도록 계됐다. 마지막 리비전만을 가져와Git분히 Perforce 라이트로 사용할 수 있다. 물론
히스토리하는 의도라면 분하지 않다.
Clone 하고 나면 Git 을 활용할 수 있는 Git 소 하나가 만들어.
$ cd myproject
$ git log --oneline --all --graph --decorate
* 70eaf78 (HEAD, p4/master, p4/HEAD, master) Initial import of
//depot/www/live/ from the state at revision #head
(- 코드 )
Perforce 서버를 가키는 “p4” 모트가 어떻게 동작하는지 모지만 Clone된다. 사실 모트도 실제하지 않는다.
$ git remote -v
394
인해보면 모트가 전없다. git-p4모트 서버의 상를 보여주기 위해 가지 Ref를 만든다. Refgit log
에서는 모트인 것처럼 보이지만 사실 Git관리하는 모트가 니라서 Push 할 수 없다.
워크플로
비를 마으니 또 수정하고 커하고 Push 해보자. 중요한 작을 마치고 팀 동들에게 유하려는 상
살펴보자.
$ git log --oneline --all --graph --decorate
* 018467c (HEAD, master) Change page title
* c0fb617 Update link
* 70eaf78 (p4/master, p4/HEAD) Initial import of //depot/www/live/ from
the state at revision #head
개 생성했고 Perforce 서버로 전송할 비가 됐다. Push 하기 전에 다른 동가 수정한 사이 있는지
인한다.
$ git p4 sync
git p4 sync
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
Import destination: refs/remotes/p4/master
Importing revision 12142 (100%)
$ git log --oneline --all --graph --decorate
* 75cd059 (p4/master, p4/HEAD) Update copyright
| * 018467c (HEAD, master) Change page title
| * c0fb617 Update link
|/
* 70eaf78 Initial import of //depot/www/live/ from the state at revision
#head
팀 동가 수정한 내용이 추가되어 master 브랜p4/master 브랜치가 라지게 되었다. Perforce브랜관리
방식Git과 달라서 Merge 을 서버로 전송하면 된다. 대신 git-p4아래와 같은 명령으로 커Rebase 하기를
한다.
$ git p4 rebase
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
No changes to import!
Rebasing the current branch onto remotes/p4/master
First, rewinding head to replay your work on top of it...
Applying: Update link
Applying: Change page title
Êindex.html | 2 +-
Ê1 file changed, 1 insertion(+), 1 deletion(-)
395
행 결과를 보면 순히 git p4 rebase git rebase p4/master 하고 git p4 sync 명령을 실한 것
처럼 보일 수 있다. 브랜치가 여러개인 상에서 훨씬 효과를 보이지만 이게 생각해도 괜찮.
이제 커히스토리가 일직선이 됐고 Perforce 서버로 유할 비를 마. git p4 submit 명령은 p4/master
master 사이에 있는 모든 커에 대해 새 Perforce 비전을 생성한다. 명령을 실하면 주로 쓰는 편기가 아래와
은 내용으로 워진.
396
# A Perforce Change Specification.
#
# Change: The change number. 'new' on a new changelist.
# Date: The date this specification was last modified.
# Client: The client on which the changelist was created. Read-
only.
# User: The user who created the changelist.
# Status: Either 'pending' or 'submitted'. Read-only.
# Type: Either 'public' or 'restricted'. Default is 'public'.
# Description: Comments about the changelist. Required.
# Jobs: What opened jobs are to be closed by this changelist.
# You may delete jobs from this list. (New changelists
only.)
# Files: What opened files from the default changelist are to be
added
# to this changelist. You may delete files from this list.
# (New changelists only.)
Change: new
Client: john_bens-mbp_8487
User: john
Status: new
Description:
Ê Update link
Files:
Ê //depot/www/live/index.html # edit
######## git author ben@straub.cc does not match your p4 account.
######## Use option --preserve-user to modify authorship.
######## Variable git-p4.skipUserNameCheck hides this message.
######## everything below this line is just the diff #######
--- //depot/www/live/index.html 2014-08-31 18:26:05.000000000 0000
+++ /Users/ben/john_bens-mbp_8487/john_bens-
mbp_8487/depot/www/live/index.html 2014-08-31 18:26:05.000000000 0000
@@ -60,7 +60,7 @@
Ê</td>
Ê<td valign=top>
ÊSource and documentation for
-<a href="http://www.perforce.com/jam/jam.html">
+<a href="jam.html">
ÊJam/MR</a>,
Êa software build tool.
Ê</td>
397
이 내용은 p4 submit 을 실했을 때 보이는 내용과 . 다만 git-p4아래에 도움이 될 만한 내용을 .
git-p4는 커이나 Changeset을 생성할 때 대한 GitPerforce에 있는 정보를 이용한다. 하지만 경우에 따라 환할
접 입력해할 수도 있다. 보내려고 하는 커의 저자가 Perforce에 계정이 없을 때도 그 저자가 작성한
Changeset으로 기록되것이다.
git-p4Git 의 내용을 바으로 Perforce Changeset시지를 생성하기 때문에 보내용을 저하고
기를 하면 된다. 개 있으로 저하고 하기를 두 번 한다. 든간에 git p4 submit
과는 아래와 같.
$ git p4 submit
Perforce checkout for depot path //depot/www/live/ located at
/Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Synchronizing p4 checkout...
... - file(s) up-to-date.
Applying dbac45b Update link
//depot/www/live/index.html#4 - opened for edit
Change 12143 created with 1 open file(s).
Submitting change 12143.
Locking 1 files ...
edit //depot/www/live/index.html#5
Change 12143 submitted.
Applying 905ec6a Change page title
//depot/www/live/index.html#5 - opened for edit
Change 12144 created with 1 open file(s).
Submitting change 12144.
Locking 1 files ...
edit //depot/www/live/index.html#6
Change 12144 submitted.
All commits applied!
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
Import destination: refs/remotes/p4/master
Importing revision 12144 (100%)
Rebasing the current branch onto remotes/p4/master
First, rewinding head to replay your work on top of it...
$ git log --oneline --all --graph --decorate
* 775a46f (HEAD, p4/master, p4/HEAD, master) Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision
#head
git p4 submit 에 가까운 Git의 명령은 push 이며 위의 과를 보면 git push 명령을 실한 것과 비하다.
Git PerforceChangeset으로 환되는 과정을 자세히 살펴보자. Git 여러개를 하나의 Perforce
Changeset으로 만들려면 git p4 submit 명령을 실하기 전에 Rebase로 커을 하나로 합치면 된다. 서버로 보
SHA-1 해시를 보면 그 이 바뀐다. git-p4Changeset으로 환할 때 각 커밋 메시지의 마지아래와 같
398
한 라인을 추가해서 달라.
$ git log -1
commit 775a46f630d8b46535fc9983cf3ebe6b9aa53145
Author: John Doe <john@example.com>
Date: Sun Aug 31 10:31:44 2014 -0800
Ê Change page title
Ê [git-p4: depot-paths = "//depot/www/live/": change = 12144]
Merge 을 서버로 전송하면 어일이 일어나는지 살펴보자. 아래와 같은 커히스토리재 처한 상이라고
생각해보자.
$ git log --oneline --all --graph --decorate
* 3be6fd8 (HEAD, master) Correct email address
* 1dcbf21 Merge remote-tracking branch 'p4/master'
|\
| * c4689fc (p4/master, p4/HEAD) Grammar fix
* | cbacd0a Table borders: yes please
* | b4959b6 Trademark
|/
* 775a46f Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision
#head
775a46f 이후에 GitPerforce 히스토리. Git으로 작에는 커, Perforce 에는 커
하나가 추가됐고 Merge 하고 서도 커이 추가됐다. 여기서 서버로 보내면 Perforce Changeset 위에 인다. 바로
Perforce 서버로 히스토리를 보내 보자.
$ git p4 submit -n
Perforce checkout for depot path //depot/www/live/ located at
/Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Would synchronize p4 checkout in /Users/ben/john_bens-mbp_8487/john_bens-
mbp_8487/depot/www/live/
Would apply
Ê b4959b6 Trademark
Ê cbacd0a Table borders: yes please
Ê 3be6fd8 Correct email address
-n 옵션--dry-run 단축 옵션으로 명령일 실제로 실하기 전에 어떻게 동작하는 지 미리 확인해 볼 수 있다.
과를 보면 로에만 있는 커3개가 Perforce Changeset으로 만들어지는 것으로 보인다. 실히 이 과는 우
원하던 바이다. 실제로 실하자.
399
$ git p4 submit
[…]
$ git log --oneline --all --graph --decorate
* dadbd89 (HEAD, p4/master, p4/HEAD, master) Correct email address
* 1b79a80 Table borders: yes please
* 0097235 Trademark
* c4689fc Grammar fix
* 775a46f Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision
#head
Rebase 하고 나서 전송한 것처럼 히스토리가 일직선이 됐다. 과는 Git으로 자유브랜치를 만들고 버Merge
해도 된다는 것을 . 히스토리Perforce지 않더라도 정할 요 없다. 물론 직Rebase 해서 Perforce
서버로 전송해도 된다.
브랜치
Perforce 프로젝트에 브랜치가 많괜찮. git-p4Perforce 브랜치를 Git 브랜치로 생각하게 만들어 .
Perforce Depot아래와 같다고 하자.
//depot
Ê └── project
Ê ├── main
Ê └── dev
dev 브랜치가 아래와 같View Spec고 있다면,
//depot/project/main/... //depot/project/dev/...
아래와 같git-p4는 자동으로 브랜치 정보를 찾아한다.
400
$ git p4 clone --detect-branches //depot/project@all
Importing from //depot/project@all into project
Initialized empty Git repository in /private/tmp/project/.git/
Importing revision 20 (50%)
Ê Importing new branch project/dev
Ê Resuming with change 20
Importing revision 22 (100%)
Updated branches: main dev
$ cd project; git log --oneline --all --graph --decorate
* eae77ae (HEAD, p4/master, p4/HEAD, master) main
| * 10d55fb (p4/project/dev) dev
| * a43cfae Populate //depot/project/main/... //depot/project/dev/....
|/
* 2b83451 Project init
Depot 경로에 “@all” 이라고 지정해주면 git-p4는 마지Changeset만을 가오는 것이 니라 지정한 경로의 모든
Changeset을 가온다. GitClone과 비하다. 프로젝트 히스토리Clone 하는데 오.
--detect-branches 옵션을 주면 git-p4Perforce브랜치를 Git브랜치로 . 정보를 Perforce
서버에 는 것이 Perforce 다운 방식이지만 git-p4접 알려수도 있다. 브랜정보를 git-p4에 전달해서 위의
와 똑 같수 있다.
$ git init project
Initialized empty Git repository in /tmp/project/.git/
$ cd project
$ git config git-p4.branchList main:dev
$ git clone --detect-branches //depot/project@all .
git-p4.branchList 정에 main:dev 을 저git-p4“main” “dev” 브랜치 이름이고 후자는
전자에서 나온 것이라 한다.
이제 git checkout -b dev p4/project/dev 하고 커으면, git p4 submit 명령을 실할 때 git-
p4똘똘하게 알브랜치를 잘 찾아 준. 게도 마지막 리비전만 받아 오는 Shallow Clone을 해하는
에서는 동시에 브랜치를 여러개 쓸 수 없다. 엄청나게 Perforce이고 여러 브랜치를 오가며 작한다면 브랜
git p4 clone 을 따로 하는 수 에 없다.
Perforce브랜치를 생성하거나 브랜합치려면 Perforce 라이트가 드시 요하다. git-p4는 이존재하는
브랜치로부터 Changeset을 가오거나 커을 보내는 일만 할 수 있다. 직선 형태Changeset 히스토리만을 유지할
수 있다. 브랜치를 Git에서 Merge 하고 Perforce 서버로 보내면 순히 변화만 기록된다. 떤 브랜치를 Merge 했는
와 같터데이터는 기록되지 않는다.
Git-Perforce 함께기 요약
git-p4 Perforce 서버를 쓰는 환경에서도 Git으로 일할 수 있게 해. 하지만 프로젝트를 관리하는 주
Perforce이고 Git은 로에서만 사용한다는 을 기한다. 따라서 Git Perforce 서버로 보내서 유할 때는
401
상 주의게 작한다. Perforce 서버로 보은 다시 보내서는 된다.
PerforceGit 라이트를 제없이 사용하고 다면 서버 관리 한이 요하다. Git FusionGit우 우
Perforce 라이트로 만들어 .
Git으로 기기
다른 VCS를 사용하는 프로젝트에서 Git을 사용하고 다면 우프로젝트를 Git으로 이전(Migrate)한다.
절에서는 Git에 들어 있는 Importer를 살펴보고 Importer를 만드는 방법도 알아본. 많이 사용하는 SCM
시스으로부터 프로젝트를 이전하는 방법을 살펴. 마도 저소를 기려고 하는 대부분의 사람들은 이 방법
참고하면 된다. 괜찮Importer가 이Git에 들어 있다.
Subversion
git svn 명하는 절을 었으면 쉽게 git svn clone 명령으로 저소를 가져올 수 있다. 오고 나서
Subversion 서버는 중지하고 Git 서버를 만들고 사용하면 된다. 히스토리 정보가 요하면 () Subversion 서버
없이 로에서 회할 수 있다.
하지만 이 가오기 기에 문제가 좀 있다. 오는데 시간이 많이 드니까 일시작하는 것이 좋다. 번째 문제는
Author 정보이다. Subversion에서는 커하려면 해당 시스계정이 있어한다. blame 이나 git svn log
명령에서 schacon 이라는 이름을 을 것이다. 이 정보를 Git 형식의 정보로 경하려면 Subversion 사용자Git
Author연결켜줘한다. Subversion 사용자이름과 Git Author 간에 할 수 있게 해한다. users.txt
라는 일을 아래와 같이 만든다.
schacon = Scott Chacon <schacon@geemail.com>
selse = Someo Nelse <selse@geemail.com>
SVN에 기록된 Author 이름을 아래 명령으로 회한다.
$ svn log --xml --quiet | grep author | sort -u | \
Ê perl -pe 's/.*>(.*?)<.*/$1 = /'
XML 형식으로 SVN 로그를 출력하고, 거기서 Author 정보만 , 된 것을 제거하고, XML 그는 버. 물론
grep, sort, perl 명령이 동작하는 시스에서만 이 명령을 사용할 수 있다. 과에 Git Author 정보를 더해서
users.txt 일을 만든다.
일을 git svn 명령에 전달하면 보다 정Author 정보를 Git 소에 남길 수 있다. git svn 명령의
clone 또는 init 명령에 --no-metadata 옵션을 주면 Subversion타데이터를 저하지 않는다 (기존
타데이터를 유지하려면 이 옵션을 사용하지 않괜찮). 해당 명령은 아래와 같.
402
$ git svn clone http://my-project.googlecode.com/svn/ \
Ê --authors-file=users.txt --no-metadata --prefix "" -s my_project
$ cd my_project
my_project 렉토리Git 소가 생성된다. 과는 아래니라,
commit 37efa680e8473b615de980fa935944215428a35a
Author: schacon <schacon@4c93b258-373f-11de-be05-5f7a86268029>
Date: Sun May 3 00:12:22 2009 +0000
Ê fixed install - go to trunk
Ê git-svn-id: https://my-project.googlecode.com/svn/trunk@94 4c93b258-
373f-11de-
Ê be05-5f7a86268029
아래와 같.
commit 03a8785f44c8ea5cdb0e8834b7c8e6c469be2ff2
Author: Scott Chacon <schacon@geemail.com>
Date: Sun May 3 00:12:22 2009 +0000
Ê fixed install - go to trunk
Author 정보가 훨씬 Gitgit-svn-id 목도 기록되지 않았다.
이제 를 할 차례. git svn 이 만들어 이상한 브랜치나 그를 제거한다. 이상한 모트 그를 모
Git 그로 . 모트 브랜치도 로컬 브랜치로 .
아래와 같그를 정한 Git 그로 만든다.
$ for t in $(git for-each-ref --format='%(refname:short)'
refs/remotes/tags); do git tag ${t/tags\//} $t && git branch -D -r $t;
done
refs/remotes/tags/ 로 시작하는 모트 브랜치를 가Lightweight 그로 만들었다.
refs/remotes 에 있는 Refs는 전부 로컬 브랜치로 만든다.
$ for b in $(git for-each-ref --format='%(refname:short)' refs/remotes);
do git branch $b refs/remotes/$b && git branch -D -r $b; done
403
대개 Subversion에서는 브랜치 하나만 보일 @xxx (xxx) 문자로 나는 가지 브랜치가 더 보일 것이다.
이런 이름의 브랜치가 존재하는 것은 "peg-revisions" 이라 부Subversion의 기때문이며 Git에서는 마
되는 기이 없다. Subversion에서 peg-revision을 다루기 위해 브랜치 이름 에 버전 자를 인 것 처럼 git
svn 시 그게 하는 것이다. peg-revision 을 사용하지 않는다면 그냥 브랜치를 제하면 된다.
$ for p in $(git for-each-ref --format='%(refname:short)' | grep @); do
git branch -D $p; done
이제 모든 와 브랜치는 Git 와 브랜치가 됐다.
마지으로 마무를 위한 과정이 하나 았다. 게도 git svn 명령이 만드는 Subversion의 기본 브랜치인
trunk 브랜치가 있다. trunk 브랜치는 Gitmaster 할을 한다고 보면 된다. Git에는 master 브랜치가 있기
때문에 여분의 trunk 브랜치는 제하자.
$ git branch -d trunk
Git 서버를 새로 추가를 하고 지금까지 작한 것을 Push 하는 일이 았다. 아래처럼 모트 서버를 추가한다.
$ git remote add origin git@my-git-server:myrepository.git
분명 모든 브랜와 태그를 Push 하고 을 것이다.
$ git push origin --all
$ git push origin --tags
모든 브랜와 태그를 Git 서버로 깔끔하게 옮겼.
Mercurial
MercurialGit의 버전은 개념이 주 비하다. 고 사실은 Git이 좀 더 유해서 Mercurial 프로젝트를 Git
프로젝트로 환하는 작주 쉽다. "hg-fast-export" 라는 을 사용하며 아래와 같이 내려 는다.
$ git clone https://github.com/frej/fast-export.git
처음 할 일은 환할 Mercurial 소 전Clone 하는 일이다.
$ hg clone <remote repo URL> /tmp/hg-repo
환에 사용할 저자 일을 하나 작성한다. MercurialChangeset에 적는 저자 정보의 형식Git에 비해
404
자유기 때문에 한 하는 것이 좋다. 저자 일은 아래와 같은 한 라인으로 된 bash 명령을 사용한다.
$ cd /tmp/hg-repo
$ hg log | grep user: | sort | uniq | sed 's/user: *//' > ../authors
프로젝트 크기에 따라 다르겠지만 위 명령을 실하면 아래와 같일이 생성된다.
bob
bob@localhost
bob <bob@company.com>
bob jones <bob <AT> company <DOT> com>
Bob Jones <bob@company.com>
Joe Smith <joe@company.com>
예제를 보면 Bob 이라는 한 사람은 적어도 가지의 다른 저자 정보를 Changeset에 기록했다. 정보는 Git에서 쓸
수 있지만 어정보는 Git에서 쓰기에 적절치 않다. Hg-fast-export 에서는 "<input>"="<output>" 규칙
사용하여 <input>` `<output>` 있다. `<input>` `<output> 문자열에는 Python
string_escape 인코을 사용하는 이스이프 문자열을 사용할 수 있다. `<input>`에서 을 수 없는 문자열을
만나는 경우 Git은 그 저자 내용을 경하지 않고 그대로 사용한다. 물론 저자 정보가 모든 Changeset에 제대로
입력있다면 이런 환 과정을 거치지 않도 된다. 예제에서는 아래와 같이 저자 정보를 수정한다.
"bob"="Bob Jones <bob@company.com>"
"bob@localhost"="Bob Jones <bob@company.com>"
"bob <bob@company.com>"="Bob Jones <bob@company.com>"
"bob jones <bob <AT> company <DOT> com>"="Bob Jones <bob@company.com>"
와 같규칙Mercurial에서 사용하고 있지만 Git에서 사용하기 브랜치나 그이름에 대해서도
방식으로 적용할 수 있다.
다음은 Git 소를 새로 만들고 환 스크트를 실한다.
$ git init /tmp/converted
$ cd /tmp/converted
$ /tmp/fast-export/hg-fast-export.sh -r /tmp/hg-repo -A /tmp/authors
-r 옵션으로 환할 Mercurial 소의 위치를 지정하고 -A 옵션으로 저자 일의 위치를 지정한다. (브랜치는 -B,
그는 -T) hg-fast-export.sh 스크트는 Mercurial Changeset을 분하여 Git"fast-import"(자세히
명한다) 쓰는 스크트를 생성한다. 명령을 실하면 아래와 같이 보여.
$ /tmp/fast-export/hg-fast-export.sh -r /tmp/hg-repo -A /tmp/authors
Loaded 4 authors
master: Exporting full revision 1/22208 with 13/0/0 added/changed/removed
files
405
master: Exporting simple delta revision 2/22208 with 1/1/0
added/changed/removed files
master: Exporting simple delta revision 3/22208 with 0/1/0
added/changed/removed files
[…]
master: Exporting simple delta revision 22206/22208 with 0/4/0
added/changed/removed files
master: Exporting simple delta revision 22207/22208 with 0/2/0
added/changed/removed files
master: Exporting thorough delta revision 22208/22208 with 3/213/0
added/changed/removed files
Exporting tag [0.4c] at [hg r9] [git :10]
Exporting tag [0.4d] at [hg r16] [git :17]
[…]
Exporting tag [3.1-rc] at [hg r21926] [git :21927]
Exporting tag [3.1] at [hg r21973] [git :21974]
Issued 22315 commands
git-fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects: 120000
Total objects: 115032 ( 208171 duplicates )
Ê blobs : 40504 ( 205320 duplicates 26117 deltas of
39602 attempts)
Ê trees : 52320 ( 2851 duplicates 47467 deltas of
47599 attempts)
Ê commits: 22208 ( 0 duplicates 0 deltas of
0 attempts)
Ê tags : 0 ( 0 duplicates 0 deltas of
0 attempts)
Total branches: 109 ( 2 loads )
Ê marks: 1048576 ( 22208 unique )
Ê atoms: 1952
Memory total: 7860 KiB
Ê pools: 2235 KiB
Ê objects: 5625 KiB
---------------------------------------------------------------------
pack_report: getpagesize() = 4096
pack_report: core.packedGitWindowSize = 1073741824
pack_report: core.packedGitLimit = 8589934592
pack_report: pack_used_ctr = 90430
pack_report: pack_mmap_calls = 46771
pack_report: pack_open_windows = 1 / 1
pack_report: pack_mapped = 340852700 / 340852700
---------------------------------------------------------------------
$ git shortlog -sn
Ê 369 Bob Jones
Ê 365 Joe Smith
406
상당히 많은 ChangesetGit 으로 환했다. Mercurial 소의 모든 그는 Git Tag환되고 브랜,
마크은 Git 브랜치로 환된다. 이제 서버 저소를 만들고 Push 하면 된다.
$ git remote add origin git@my-git-server:myrepository.git
$ git push origin --all
Bazaar
Bazaar 또한 Git과 비DVCS 이기 때문에 Bazaar 소를 Git 소로 환하는 것은 운편이다.
을 하려면 bzr-fastimport 플러그인이 요하다.
bzr-fastimport 그인 다로드
bzr-fastimport 플러그인을 치하는 방식Unix 한 환경과 Windows 환경이 우 다. Unix
환경에서는 운영제에서 제하는 키지 관리자를 bzr-fastimport 키지를 치하는 방법이 가쉽다.
예를 들어 Debian 이나 Linux라면 다음과 `bzr-fastimport`치할 수 있다.
$ sudo apt-get install bzr-fastimport
RHEL이나 Linux라면 다음과 `bzr-fastimport`치할 수 있다.
$ sudo yum install bzr-fastimport
Fedora release 22 이상이라면 dnf를 사용하여 `bzr-fastimport`치할 수 있다.
$ sudo dnf install bzr-fastimport
키지 관리자 도가 없는 경우라면 다음과 Python을 이용하여 플러그인을 치할 수 있다.
$ mkdir --parents ~/.bazaar/plugins # creates the necessary folders
for the plugins
$ cd ~/.bazaar/plugins
$ bzr branch lp:bzr-fastimport fastimport # imports the fastimport
plugin
$ cd fastimport
$ sudo python setup.py install --record=files.txt # installs the plugin
bzr-fastimport 플러그인을 사용하려면 Pythonfastimport 또한 요하다. 다음과 은 명령으로
fastimport Python 치되어 있는지, 치를 어떻게 하는지 살펴볼 수 있다.
407
$ python -c "import fastimport"
Traceback (most recent call last):
Ê File "<string>", line 1, in <module>
ImportError: No module named fastimport
$ pip install fastimport
방식동작하지 않는 경우 https://pypi.python.org/pypi/fastimport/ 에서 바로 내려 거나 도움을 을 수
있다.
Windows 에서 `bzr-fastimport`Git 치시 Standalone 버전이나 기본 설(모든 스가 정되)의 경우 함
치된다. 따라서 따로 더 치 작요하지 않다.
이 시에서 Bazaar 소를 Git 소로 환할 때 브랜치를 하나만 사용하는지 브랜치를 여러개 사용하는지에
따라 환 작이 달라.
한 브랜치만 사용하는 프로젝트
cd 명령으로 Bazaar 소가 위치한 디렉토리로 이동하고, Git 소를 init 한다.
$ cd /path/to/the/bzr/repository
$ git init
다음과 이 간한 명령으로 Bazaar 소를 Git 소로 환할 수 있다.
$ bzr fast-export --plain . | git fast-import
프로젝트 크기에 따라 수 은 수 분 내에 Bazaar 소의 내용이 Git 소에 담길 것이다.
메인 브랜치 하나와 작업 브랜치 하나를 사용하는 프로젝트
여러 브랜치를 사용하는 Bazaar 소도 Git 소로 환할 수 있다. 예를 들어 개의 브랜치를 사용한다고
가정해보자. 브랜치는 브랜(myProject.trunk), 다른 브랜치는 작업 브랜(myProject.work) 인 경우가
있을 수 있다.
$ ls
myProject.trunk myProject.work
이 위치에서 새로 Git 소를 init 하고 cd 명령으로 이동한다.
$ git init git-repo
$ cd git-repo
408
trunk 브랜치의 내용을 master 브랜치로 가온다.
$ bzr fast-export --export-marks=../marks.bzr ../myProject.trunk | \
git fast-import --export-marks=../marks.git
work 브랜치의 내용을 work 브랜치로 가온다.
$ bzr fast-export --marks=../marks.bzr --git-branch=work ../myProject.work
| \
git fast-import --import-marks=../marks.git --export-marks=../marks.git
git branch 명령으로 master 브랜work 브랜치를 인할 수 있다. 히스토리인하여 전히 저
브랜치의 내용이 환된 것을 인한 후 위 과정에서 생성된 marks.bzr, marks.git 일을 제한다.
Staging Area를 동기
위 과정을 실하고 나면 하나 은 여러 브랜치의 히스토리Git 소 히스토리환되었지만 Staging Area와 워
렉토리`HEAD`동기가 이루어지지 않은 상이다. 다음 명령으로 쉽게 `HEAD`동기를 시수 있다.
$ git reset --hard HEAD
.bzrignore로 무시하는 파일 동일하게 무시
일 무시하기 내용을 살펴볼 차례이다. 선 먼저 해할 일은 .bzrignore 일을 .gitignore 일로 이름을
경하는 것이다. .bzrignore 일이 "!!", "RE:" 문자열로 시작하는 을 포함한다면 이를 적절한 Git 으로
경하여 .gitignore 일에 작성해한다.
위 작을 마치고 난 후 이제 이 경사에 대한 커을 작성할 차례이다.
$ git mv .bzrignore .gitignore
$ # modify .gitignore if needed
$ git commit -am 'Migration from Bazaar to Git'
서버로 저장소 전
고생하수다. 이제 서버 모트 저소로 Push 할 수 있다.
$ git remote add origin git@my-git-server:mygitrepository.git
$ git push origin --all
$ git push origin --tags
게 전송한 모트 저소를 Git 소로 사용할 수 있다.
409
Perforce
Perforce 프로젝트를 Git으로 환해 보자. PerforceGit으로 환하는 방법git-p4Perforce Git
Fusion을 이용하는 방법 두 가지다.
Perforce Git Fusion
Git Fusion을 사용한다면 어려게 없다. 그저 프로젝트 정보, 사용자 , 브랜치를 일에 정하고(Git
Fusion에서 다) Perforce 소를 Clone 하기만 하면 된다. Git Fusion은 마치 Git 소를 Clone 한 것 처럼
게 해. Clone 했으면 Git 서버에 Push 한다. 심지어 다시 Perforce 서버로 Push 해도 된다.
Git-p4
Git-p4Import 로 사용할 수 있다. Perforce Public Depot에 있는 Jam 프로젝트를 Git으로 옮겨보자.
Perforce Depot의 주소를 P4PORT 환경수에 정한다.
$ export P4PORT=public.perforce.com:1666
지금 하는 예제를 실제로 해보려면 접Perforce Depot요하다. 여기서는
public.perforce.com 사이트의 개된 Depot을 이용하지만 접한 다른 Depot으로 해도
괜찮.
git p4 clone 명령으로 Perforce 서버에서 Jam 프로젝트를 가온다. 이 명령에 Depot, 프로젝트 경로, 프로젝트를
져올 경로를 주면 된다.
$ git-p4 clone //guest/perforce_software/jam@all p4import
Importing from //guest/perforce_software/jam@all into p4import
Initialized empty Git repository in /private/tmp/p4import/.git/
Import destination: refs/remotes/p4/master
Importing revision 9957 (100%)
예제로 사용하는 이 프로젝트는 브랜치가 하나뿐이다. Clone 할 프로젝트에 브랜치가 여러개 있거나 브랜치가
렉토리있다면 --detect-branches 옵션을 사용하여 브랜치 정보를 Git 소로 그대로 들고수 있다.
브랜 에서 자세한 내용을 살펴볼 수 있다.
여기까지만 해도 이상 한 것이다. p4import 렉토리로 이동해서 git log 명령을 실하면 프로젝트 정보를 볼 수
있다.
410
$ git log -2
commit e5da1c909e5db3036475419f6379f2c73710c4e6
Author: giles <giles@giles@perforce.com>
Date: Wed Feb 8 03:13:27 2012 -0800
Ê Correction to line 355; change </UL> to </OL>.
Ê [git-p4: depot-paths = "//public/jam/src/": change = 8068]
commit aa21359a0a135dda85c50a7f7cf249e4f7b8fd98
Author: kwirth <kwirth@perforce.com>
Date: Tue Jul 7 01:35:51 2009 -0800
Ê Fix spelling error on Jam doc page (cummulative -> cumulative).
Ê [git-p4: depot-paths = "//public/jam/src/": change = 7304]
로그를 살펴보면 커마다 git-p4 라는 ID 목이 들어가 있다. 나중에 Perforce Change Number요해질 수도
있으니 커에 그대로 유지하는 편이 좋다. 하지만 ID를 지우고자 한다면 유하기 전인 이 계에서 지운다.
git filter-branch 명령으로 한제한다.
$ git filter-branch --msg-filter 'sed -e "/^\[git-p4:/d"'
Rewrite e5da1c909e5db3036475419f6379f2c73710c4e6 (125/125)
Ref 'refs/heads/master' was rewritten
git log 명령을 실하면 모든 SHA-1 경됐고 커밋 메시지에서 git-p4 목이 제된 것을 인할 수
있다.
$ git log -2
commit b17341801ed838d97f7800a54a6f9b95750839b7
Author: giles <giles@giles@perforce.com>
Date: Wed Feb 8 03:13:27 2012 -0800
Ê Correction to line 355; change </UL> to </OL>.
commit 3e68c2e26cd89cb983eb52c024ecdfba1d6b3fff
Author: kwirth <kwirth@perforce.com>
Date: Tue Jul 7 01:35:51 2009 -0800
Ê Fix spelling error on Jam doc page (cummulative -> cumulative).
이제 새 Git 서버에 Push 하면 된다.
411
TFS
팀이 TFVCGit으로 기기로 했다면 가한 많은 데이터를 기고자 할 것이다. 에서 git-tfsgit-tf를 둘 다
명했지만 여기서는 git-tfs만 사용한다. git-tfs브랜치를 지원하지만, git-tf로는 어렵다.
여기서는 단방환만 다. 환한 Git 소는 원 TFVC 와 아무런 연결가 없다.
저 사용자이름을 대. TFVC ChangesetAuthor 드는 형식이 자유지만 Git에는 사람이 을 수 있는
이름과 E-mail 주소로 정해있다. 이 정보는 커드라인 라이트인 tf 로 가온다.
PS> tf history $/myproject -recursive > AUTHORS_TMP
이 명령어는 프로젝트의 모든 Chagneset을 가져와AUTHORS_TMP 일에 저한다. AUTHORS_TMP 일에서
번째 열의 'User' 정보를 추출해서 사용한다. 추출할 때 아래 이어지는 cut 명령에서 사용할 `11-20`터를
하기 위해 몇 번 해서 해당 드를 자를 수 있는 적당한 자를 알한다.
PS> cat AUTHORS_TMP | cut -b 11-20 | tail -n+3 | sort | uniq > AUTHORS
cut 명령어는 각 라인에서 11-20의 문자열만 한다. tail 명령어로는 라인을 .
과를 sort, uniq 명령에 이프로 보내서 중을 지운다. 고는 AUTHORS 일에 저한다. 그 다음은 수동으로
한다. git-tfs요로 하는 일의 포아래와 같.
DOMAIN\username = User Name <email@address.com>
`=`왼쪽TFVC“User” 드고 오른Git 에 사용할 개발자 정보다.
일을 만들었으면 해당 TFVC 프로젝트를 Clone 한다.
PS> git tfs clone --with-branches --authors=AUTHORS
https://username.visualstudio.com/DefaultCollection $/project/Trunk
project_git
고 커밋 메시지 git-tfs-id 부분을 지운다. 아래 명령어를 사용하면 된다.
PS> git filter-branch -f --msg-filter 'sed "s/^git-tfs-id:.*$//g"' '--'
--all
Git-bash 환경에서 sed 명령어로 “git-tfs-id:” 로 시작하는 로 바. 그럼 Git은 그 라인을 무시한다.
다 됐다. 모트를 새로 추가하고 모든 브랜치를 Push 한다. 고 나서 팀원들과 Git으로 작을 시작하면 된다.
412
Importer 만들기
사용하는 VCS서 살펴시스니면 인터에서 적당한 Importer찾아한다. CVS, Clear Case, Visual
Source Safe 은 시스Importer가 좋은게 많다. 심지어 순히 디렉토리 아Importer에도 좋은게 있다.
사람들이 잘 안쓰는 시스을 사용하고 있는데 적당한 Importer를 못 았거나 부해서 좀 더 고한다면 git
fast-import 를 사용한다. 이 명령은 표준입력으로 데이터를 입력는다. Git의 내부 에서 배우는 저수명령어
내부 객체접 다루는 것보다 훨씬 쉽다. 저 사용하는 VCS에서 요한 정보를 수해서 표준출력으로 출력하는
스크트를 만든다. 고 그 과를 git fast-import 표준입력으로 보.
Importer를 작성해보자. current 렉토리에서 작하고 back_YYYY_MM_DD 이라는 디렉토리에 백하면서
진행했던 프로젝트를 살펴 보자. Importer를 만들 때 디렉토리 아래와 같.
$ ls /opt/import_from
back_2014_01_02
back_2014_01_04
back_2014_01_14
back_2014_02_03
current
Importer를 만들기 전에 우Git이 어떻게 데이터를 저하는지 알아야 한다. 알고 있Git은 기적으로
냅샷을 가키는 커연결스트이다. 냅샷, 그걸 가키는 커은 또 , 그 커의 순서가
어떻게 되는지 fast-import 에 알려 한다. 이 것이 해할 일의 전부다. 그러면 디렉토리마다 스냅샷을 만들고,
냅샷을 가키는 커를 만들고, 이전 커연결 .
정책 구현하기 절에서 했던 것 처럼 Ruby로 스크트를 작성한다. 책에서 계속 스크트를 작성할 때 Ruby로 해왔고,
기도 쉽기에 Ruby. 하지만 자신에게 한 것을 사용해서 표준출력으로 적절한 정보만 출력할 수 있으면 된다.
Windows에서는 라인 바문자에 CR(Carriage Return) 문자가 들어가지 않도록 주의해한다. git fast-
import 명령은 Windows에서도 라인 바문자로 CRLF 문자가 니라 LF(Line Feed) 문자만 용한다.
해당 디렉토리로 이동해서 어렉토리가 있는지 살펴. 하위 디렉토리마다 스냅샷 하나가 되고 커하나가
된다. 하위 디렉토리를 이동하면서 요한 정보를 출력한다. 적인 로아래와 같.
413
last_mark = nil
# loop through the directories
Dir.chdir(ARGV[0]) do
Ê Dir.glob("*").each do |dir|
Ê next if File.file?(dir)
Ê # move into the target directory
Ê Dir.chdir(dir) do
Ê last_mark = print_export(dir, last_mark)
Ê end
Ê end
end
각 디렉토리에서 print_export 를 호출하는데 이 함수는 아규먼트로 디렉토리와 이전 스냅샷 Mark를 전달
냅샷 Mark환한다. 서 적절히 연결 수 있다. fast-import 에서 “Mark는 커식별자를 한다.
을 하나 만들면 “Mark이 만들어 이 “Mark로 다른 커연결 . print_export 에서 우
하는 일은 각 디렉토리 이름으로 “Mark를 생성하는 것이다.
mark = convert_dir_to_mark(dir)
Mark는 정수 을 사용해하기 때문에 디렉토리를 배열에 고 그 IndexMark로 사용한다. 아래와 같이 작성한다.
$marks = []
def convert_dir_to_mark(dir)
Ê if !$marks.include?(dir)
Ê $marks << dir
Ê end
Ê ($marks.index(dir) + 1).to_s
end
각 커을 가키는 정수 Mark를 만들었고 다음에는 커밋 메타데이터에 정보가 요하다. 는 디렉토리
이름에 있는 것을 가다 사용한다. print_export 두 번째 라인은 아래와 같.
date = convert_dir_to_date(dir)
convert_dir_to_date 아래와 같이 정의한다.
414
def convert_dir_to_date(dir)
Ê if dir == 'current'
Ê return Time.now().to_i
Ê else
Ê dir = dir.gsub('back_', '')
Ê (year, month, day) = dir.split('_')
Ê return Time.local(year, month, day).to_i
Ê end
end
시간는 정수 형태환한다. 마지으로 타정보에 요한 것은 Author인데 이 것은 전수 하나로 정해서
사용한다.
$author = 'John Doe <john@example.com>'
이제 Importer에서 출력할 커데이터는 다 비했다. 이제 출력해보자. 사용할 브랜, 해당 커관련Mark,
터 정보, 밋 메시지, 이전 커을 출력한다. 코드로 만들면 아래와 같.
# print the import information
puts 'commit refs/heads/master'
puts 'mark :' + mark
puts "committer #{$author} #{date} -0700"
export_data('imported from ' + dir)
puts 'from :' + last_mark if last_mark
시간대(-0700) 정보는 편의상 하드코으로 처했다. 각자의 시간대에 는 오프정해한다. 밋 메시지는
아래와 같형식을 따라한다.
data (size)\n(contents)
형식“data라는 , 을 데이터의 크기, 라인 바문자, 실 데이터로 성된다. 형식을 여러 에서 사용해
export_data 라는 Helper 소드로 만들어 놓는게 좋다.
def export_data(string)
Ê print "data #{string.size}\n#{string}"
end
이제 은 것은 스냅샷일 내용를 포함시키는 것 뿐이다. 렉토리있기 때문에 어렵지 않다.
deleteall 이라는 명령을 출력하고 그 에 모든 일의 내용을 출력한다. 그러면 Git은 스냅샷한다.
415
puts 'deleteall'
Dir.glob("**/*").each do |file|
Ê next if !File.file?(file)
Ê inline_data(file)
end
Note: 대부분의 VCS비전을 커간의 변화로 생각하기 때문에 fast-import에 추가//경된 부분만 입력할 수도
있다. 냅샷 사이의 이를 해서 fast-import에 넘수도 있지만 훨씬 복잡하다. 수 있는 데이터는 전부 Git
Git이 계하게 해한다. 게 해한다면 어떻게 데이터를 전달해하는지 fast-import ManPage
참고하라.
일 정보내용은 아래와 같형식으로 출력한다.
M 644 inline path/to/file
data (size)
(file contents)
644일의 모드를 나타(행파일이라면 755로 지정해한다). inline 다음 라인 부터는 일 내용이라 하는
것이다. inline_data 소드는 아래와 같.
def inline_data(file, code = 'M', mode = '644')
Ê content = File.read(file)
Ê puts "#{code} #{mode} inline #{file}"
Ê export_data(content)
end
일 내용은 커밋 메시지랑 같방법을 사용하기 때문에 서 만들어 놓은 export_data 소드를 다시 이용한다.
마지으로 다음에 커Mark 환한다.
return mark
Windows에서 실할 때는 추가 작이 하나 더 요하다. 에서 기했지만 WindowsCRLF
사용하지만 git fast-import LF를 사용한다. 이 문제를 해하려면 RubyCRLF 대신 LF
사용하도록 알려 한다.
$stdout.binmode
모든게 끝났. 스크트 코드는 아래와 같:
#!/usr/bin/env ruby
416
$stdout.binmode
$author = "John Doe <john@example.com>"
$marks = []
def convert_dir_to_mark(dir)
Ê if !$marks.include?(dir)
Ê $marks << dir
Ê end
Ê ($marks.index(dir)+1).to_s
end
def convert_dir_to_date(dir)
Ê if dir == 'current'
Ê return Time.now().to_i
Ê else
Ê dir = dir.gsub('back_', '')
Ê (year, month, day) = dir.split('_')
Ê return Time.local(year, month, day).to_i
Ê end
end
def export_data(string)
Ê print "data #{string.size}\n#{string}"
end
def inline_data(file, code='M', mode='644')
Ê content = File.read(file)
Ê puts "#{code} #{mode} inline #{file}"
Ê export_data(content)
end
def print_export(dir, last_mark)
Ê date = convert_dir_to_date(dir)
Ê mark = convert_dir_to_mark(dir)
Ê puts 'commit refs/heads/master'
Ê puts "mark :#{mark}"
Ê puts "committer #{$author} #{date} -0700"
Ê export_data("imported from #{dir}")
Ê puts "from :#{last_mark}" if last_mark
Ê puts 'deleteall'
Ê Dir.glob("**/*").each do |file|
Ê next if !File.file?(file)
Ê inline_data(file)
Ê end
Ê mark
end
417
# Loop through the directories
last_mark = nil
Dir.chdir(ARGV[0]) do
Ê Dir.glob("*").each do |dir|
Ê next if File.file?(dir)
Ê # move into the target directory
Ê Dir.chdir(dir) do
Ê last_mark = print_export(dir, last_mark)
Ê end
Ê end
end
스크트를 실하면 아래와 같이 출력된다.
$ ruby import.rb /opt/import_from
commit refs/heads/master
mark :1
committer John Doe <john@example.com> 1388649600 -0700
data 29
imported from back_2014_01_02deleteall
M 644 inline README.md
data 28
# Hello
This is my readme.
commit refs/heads/master
mark :2
committer John Doe <john@example.com> 1388822400 -0700
data 29
imported from back_2014_01_04from :1
deleteall
M 644 inline main.rb
data 34
#!/bin/env ruby
puts "Hey there"
M 644 inline README.md
(...)
렉토리를 하나 만들고 git init 명령을 실해서 Git 프로젝트를 만든다. 고 그 프로젝트 디렉토리
이동해서 이 명령의 표준출력을 git fast-import 명령의 표준입력으로 연결한다(pipe).
418
$ git init
Initialized empty Git repository in /opt/import_to/.git/
$ ruby import.rb /opt/import_from | git fast-import
git-fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects: 5000
Total objects: 13 ( 6 duplicates )
Ê blobs : 5 ( 4 duplicates 3 deltas of
5 attempts)
Ê trees : 4 ( 1 duplicates 0 deltas of
4 attempts)
Ê commits: 4 ( 1 duplicates 0 deltas of
0 attempts)
Ê tags : 0 ( 0 duplicates 0 deltas of
0 attempts)
Total branches: 1 ( 1 loads )
Ê marks: 1024 ( 5 unique )
Ê atoms: 2
Memory total: 2344 KiB
Ê pools: 2110 KiB
Ê objects: 234 KiB
---------------------------------------------------------------------
pack_report: getpagesize() = 4096
pack_report: core.packedGitWindowSize = 1073741824
pack_report: core.packedGitLimit = 8589934592
pack_report: pack_used_ctr = 10
pack_report: pack_mmap_calls = 5
pack_report: pack_open_windows = 2 / 2
pack_report: pack_mapped = 1457 / 1457
---------------------------------------------------------------------
적으로 나면 여기서 보여주는 것처럼 어떻게 됐는지 계를 보여. 이 경우브랜14개 그
13개가 포트됐다. 이제 git log 명령으로 히스토리 조회가 가하다.
$ git log -2
commit 3caa046d4aac682a55867132ccdfbe0d3fdee498
Author: John Doe <john@example.com>
Date: Tue Jul 29 19:39:04 2014 -0700
Ê imported from current
commit 4afc2b945d0d3c8cd00556fbe2e8224569dc9def
Author: John Doe <john@example.com>
Date: Mon Feb 3 01:00:00 2014 -0700
Ê imported from back_2014_02_03
419
깔끔하게 Git 소가 성됐다. 이 시에서는 무것도 Checkout 하지 않았기 때문에 렉토리아직 아
일도 없다. master 브랜치로 Reset 해서 일을 Checkout 한다.
$ ls
$ git reset --hard master
HEAD is now at 3caa046 imported from current
$ ls
README.md main.rb
fast-import 명령으로 많은 일을 할 수 있다. 모드를 정하고, 바이너리 데이터를 다루고, 브랜치를 여러 개 다루고,
Merge 하고, 그를 달고, 진행을 보여 주고, 등등 무수히 많은 일을 할 수 있다. Git 소스의 contrib/fast-
import 렉토리복잡한 상을 다루는 예제가 많다.
요약
다른 VCS 서버의 라이트로 Git을 사용하거나, 다른 VCS 소를 Git 소로 실 없이 기는 방법에 대해 알
. 다음 에서는 Git 내부를 까. 요하다면 바이트 하나하나 다루는 것도 가하다.
420
Git의 내부
여기까지 다 고 왔든지 바로 여기부터 보기 시작했던지 간에 이제 마지막 장이다. 번 장Git이 어떻게 구현돼 있고
내부적으로 어떻게 동작하는지 명한다. Git마나 유용하고 력한지 이해하려면 이 의 내용을 아야 한다.
보자에게 불필요한 내용이라고 이기하는 사람들도 있다. 자는 내용을 책의 가
마지었고 자가 스스로 저 볼지 나중에 볼지 선택할 수 있도록 했다.
자 이제 적으로 살펴보자. Git은 기적으로 Content-addressable 일 시스이고 그 위에 VCS 사용자
인터이스가 있는 구조. 깔끔한 정의는 니지만, 이 무인지는 차차 알게 된다.
Git 기에는 (1.5 이전 버전) 사용자 인터이스가 훨씬 복잡했었다. VCS니라 일 시스강조했기 때문이었다.
최근 몇 년간 Git은 다른 VCS처럼 쉽고 간하게 사용자 인터이스를 다어 왔다. 하지만, 여전히 복잡하고 배우기
어렵다는 이 있다.
Content-addressable 일 시스은 정한 것이저 다. 고 나서 데이터 전송 원를 배우고
마지에는 저소를 관리하는 까지 배운다.
Plumbing 명령과 Porcelain 명령
이 책은 checkout, branch, remote 30여가지의 명령어로 Git를 어떻게 사용하는지 명한다. Git은 원
사용하기 쉽게 만든 VCS라기보다는 VCS를 위한 이다. 적으로 우 많은 저수명령어로 있고 이
명령어들을 UNIX 스타일로 어서 실하거나 스크트로 만들어 사용하도록 계했다. 이러한 저수의 명령어는
“Plumbing” 명령어라고 부고 좀 더 사용자에게 한 사용자용 명령어는 “Porcelain명령어라고 부른다.
이 책의 은 주로 Porcelain 명령어만 사용했다. 하지만, 에서는 저수명령인 Plumbing 명령어를 주로
사용한다. 이 명령으로 Git의 내부구조에 접할 수 있고 실제로 , 게 작동하는지도 살펴볼 수 있다. Plumbing
명령어는 접 커드라인에서 실하기보다 새로운 도를 만들거나 각자 요한 스크트를 작성할 때 사용한다.
새로 만든 디렉토리나 이미 파일이 있는 디렉토리에서 git init 명령을 실하면 Git은 데이터를 저하고 관리하는
.git 렉토리를 만든다. 이 디렉토리사하기만 해도 저소가 백된다. 은 기적으로 이 디렉토리에 대한
내용을 명한다. 새로 저소를 만들면 .git 렉토리 구조는 다음과 :
$ ls -F1
config
description
HEAD
hooks/
info/
objects/
refs/
이 외에 다른 일들이 더 있지만, 이 상git init 명령을 실후에 보이는 새 저소의 모습이다.
description 일은 기적으로 GitWeb 프로그에서만 사용하기 때문에 이 일은 신경쓰지 않도 된다. config
일에는 해당 프로젝트에만 적용되는 옵션이 들어 있다. info 렉토리.gitignore 일처럼 무시할 일의
을 적어 이다. 하지만 .gitignore 일과는 달Git으로 관리되지 않는다. hooks 렉토리에는
라이이나 서버 이 위치한다. 관련 내용은 Git Hooks 에서 명한다.
421
이제 가지 목은 모중요한 목이다. HEAD , index , objects 렉토리, refs 렉토리
았다. 목이 Git의 핵심이다. objects 렉토리는 모든 컨텐트를 저하는 데이터이스이고 refs
렉토리에는 커의 포인터(브랜, , 모트 등)를 저한다. HEAD 일은 Checkout 브랜치를
키고 index 일은 Staging Area의 정보를 저한다. 각 절마다 주제를 나Git이 어떻게 동작하는지 자세히
명한다.
Git
GitContent-addressable 일시스이다. 이게 무하면 Git의 핵심은 순한 Key-Value(- ,
이름과 일 데이터) 데이터 저소라는 것이다. 떤 형식의 데이터라도 을 수 있고 해당 Key제든지 데이터를
다시 가져올 수 있다.
이 개념을 명하기 위해 한 Plumbing 명령어를 예로 들면 git hash-object 명령이 있다. 이 명령에 데이터를 주면
.git/objects 렉토리(object 데이터이스)에 저하고 그 데이터에 접할 수 있는 key를 알려주며 이
key는 저소 내에서 유일하다.
Git 소를 새로 만들어 보자. objects 렉토리가 들어 있는지 인해 보면 새 저소이기 때문에
무 것이 없을 것이다.
$ git init test
Initialized empty Git repository in /tmp/test/.git/
$ cd test
$ find .git/objects
.git/objects
.git/objects/info
.git/objects/pack
$ find .git/objects -type f
아직 렉토리일 뿐 일은 무것도 없다. Gitinit 명령으로 저소를 할 때 objects 렉토리를 만들고
pack info 렉토리도 만든다. git hash-object 명령을 사용하여 Git 데이터이스에 새 데이터 개
접 저해보자.
$ echo 'test content' | git hash-object -w --stdin
d670460b4b4aece5915caf5c68d12f560a9fe3e4
git hash-object 명령은 주어지는 데이터를 저하고 이 데이터에 접하기 위한 key환한다. -w 옵션
실제로 저한다. -w 가 없으면 저하지 않고 key만 보여. --stdin 옵션을 주면 표준입력으로 입력되는
데이터를 는다. 옵션이 없으면 일 경로를 알려한다.
git hash-object 명령이 출력하는 것은 40이의 해시다. 이 해시는 더 정보데이터 모에 대한
SHA-1 해시이다. 더 정보는 차차 자세히 살펴볼 것이다. Git이 저한 데이터를 알보자.
$ find .git/objects -type f
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
422
objects 렉토리일이 하나 새로 생. 데이터는 새로 만든 일에 저하며 Git은 데이터를 저할 때 데이터
더로 생성한 SHA-1 으로 일 이름을 는다. 해시의 처음 두 글자를 따서 디렉토리 이름에 사용하고 나
38자를 일 이름에 사용한다.
에서와 같Git 데이터이스에 개를 저하고 나면 이후에는 git cat-file 명령으로 저한 데이터를
수 있다. 이 명령은 Git 를 살펴보고 을 때 가이버처럼 사용할 수 있다. git cat-file 명령에 -p 옵션을 주면
일 내용이 출력된다.
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
test content
다시 한 데이터를 Git 소에 추가하고 보자. Git일 버전을 관리하는 방식을 이해할 수 있도록 가상의
을 만들어 살펴. 일을 하나 만들고 Git 소에 저한다:
$ echo 'version 1' > test.txt
$ git hash-object -w test.txt
83baae61804e65cc73a7201a7252750c76066a30
고 그 일을 수정하고 다시 저한다.
$ echo 'version 2' > test.txt
$ git hash-object -w test.txt
1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
이제 데이터이스에는 데이터가 가지 버전으로 저장돼 있다.
$ find .git/objects -type f
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
와 같이 되면 이제 로렉토리test.txt 일을 지우더라도 Git을 사용하여 test.txt 일을 번째 버전의
내용으로 되돌릴 수 있다.
$ git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt
$ cat test.txt
version 1
두 번째 버전을 다시 적용한다.
423
$ git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a > test.txt
$ cat test.txt
version 2
일의 SHA-1 키를 외서 사용하는 것은 무 어렵다. 게다가 원래 파일의 이름은 저하지도 않았다. 일 내용만
했을 뿐이다. 이런 의 개Blob 라고 부른다. git cat-file -t 명령으로 SHA-1 key를 입력하면
키는 해당 개가 무인지 인할 수 있다.
$ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
blob
Tree
다음은 Tree 를 살펴보자. Tree 일 이름을 저한다. 일 여러 개를 한꺼번에 저할 수도 있다. Git
일 시스과 비방법으로 저하지만 좀 더 순하다. 모든 것을 TreeBlob 로 저한다. Tree
스의 디렉토리에 대되고 BlobInode나 일반 파일에 대된다. Tree 하나는 목을 여러 개 가질 수 있다.
고 그 목에는 Blob 나 하위 Tree 를 가키는 SHA-1 포인터, 일 모드, 타입, 일 이름이 들어 있다.
simplegit 프로젝트의 마지Tree 를 살펴보자.
$ git cat-file -p master^{tree}
100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README
100644 blob 8f94139338f9404f26296befa88755fc2598c289 Rakefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 lib
master^{tree} 문은 master 브랜치가 가키는 Tree 한다. lib 목은 디렉토리인데 Blob
니고 다른 Tree .
$ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b simplegit.rb
여러분이 사용하는 이 어것인가에 따라 master^{tree} 표현식이 오를 일으수도 있다.
Windows 에서 CMD^ 문자는 이스이프 기호로 사용한다. ^ 문자를 제대로 사용하려면 git
cat-file -p master^^{tree} 형태로 사용해한다. PowerShell을 사용한다면 {}
문자를 사용하는 터의 경우 따' 를 사용해제대로 된 입력이 가하다. git cat-
file -p 'master^{tree}' 형태로 사용해한다.
ZSH 을 사용한다면 ^ 문자는 Glob 으로 사용되기 때문에 git cat-file -p "master^
{tree}" 형태로 사용해한다.
Git이 저하는 데이터는 대강 아래 .
424
그림 148. 순화한 Git 데이터 모델.
Tree 를 만들어 보자. Git은 일적으로 Staging Area(Index)의 상대로 Tree 를 만들고 기록한다.
Tree 를 만들려면 우Staging Area일을 추가해서 Index를 만들어한다. Plumbing 명령인
update-index 명령으로 test.txt 일만 들어 있는 Index를 만든다. 이 명령어는 일을 인위적으로 Staging
Area에 추가하는 명령이다. 아직 Staging Area에 없는 일이기 때문에 --add 옵션꼭 줘한다(사실 아직 Staging
Area정하지 않았다). 고 디렉토리에 있는 일이 니라 데이터이스에 있는 일을 추가하는 것이기 때문에
--cacheinfo 옵션요하다. 일 모드, SHA-1 해시, 일 이름 정보도 입력한다.
$ git update-index --add --cacheinfo 100644 \
Ê 83baae61804e65cc73a7201a7252750c76066a30 test.txt
여기서 일 모드는 보일을 나타내는 100644 로 지정했다. 행파일이라면 100755 로 지정하고 심볼
크라면 120000 으로 지정한다. 이런 일 모드는 유스에서 가했지만, 스 모드를 전부 사용하지는 않는다.
Blob 일에는 이 세 가지 모드만 사용한다. 렉토리나 서에는 다른 모드를 사용한다.
Staging AreaTree 로 저할 때는 git write-tree 명령을 사용한다. write-tree 명령은 Tree
없으면 자동으로 생성하-w 옵션요 없다.
425
$ git write-tree
d8329fc1cc938780ffdd9f94e0d364e0ea74f579
$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
100644 blob 83baae61804e65cc73a7201a7252750c76066a30 test.txt
다음과 git cat-file 명령으로 이 개Tree 라는 것을 인할 수 있다.
$ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579
tree
일을 새로 하나 추가하고 test.txt 일도 두 번째 버전을 만든다. 고 나서 Tree 를 만든다.
$ echo 'new file' > new.txt
$ git update-index --add --cacheinfo 100644 \
Ê 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt
$ git update-index --add new.txt
일인 new.txt 일과 새로운 버전의 test.txt 일까지 Staging Area에 추가했다. 재 상Staging
Area를 새로운 Tree 로 기록하면 어떻게 보이는지 살펴보자.
$ git write-tree
0155eb4229851634a0f03eb265b69f5a2d56f341
$ git cat-file -p 0155eb4229851634a0f03eb265b69f5a2d56f341
100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt
Tree 에는 일이 개 있고 test.txt 일의 SHA 두 번째 버전인 1f7a7a1 이다. 난 걸 해보자.
처음에 만든 Tree 를 하위 디렉토리로 만들 수 있다. git read-tree 명령으로 Tree Staging Area
추가한다. --prefix 옵션을 주면 Tree 를 하위 디렉토리로 추가할 수 있다.
$ git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579
$ git write-tree
3c4e9cd789d88d8d89c1073707c3585e41b0e614
$ git cat-file -p 3c4e9cd789d88d8d89c1073707c3585e41b0e614
040000 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579 bak
100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt
Tree 렉토리를 만들면 bak 이라는 하위 디렉토리가 생. bak 렉토리 안에는
test.txt 일의 처음 버전이 들어 있다. 아래와 구조로 데이터가 저된다.
426
그림 149. 현재 Git 데이터 구조.
커밋 개
각기 다른 스냅샷을 나타내는 Tree 를 세 개 만들었다. 아직 남은 어려운 은 여전히 이 스냅샷러오려면 SHA-1
을 기하고 있어한다는 이다. 냅샷, , 했는지에 대한 정보는 예 없다. 이런 정보는 커
에 저된다.
commit-tree 명령으로 만든다. 이 명령에 커에 대한 명과 Tree SHA-1 한 개를 넘.
서 저번째 Tree를 가지고 아래와 같이 만들어 .
$ echo 'first commit' | git commit-tree d8329f
fdf4fc3344e67ab068f836878b6c4951e3b15f3d
물론 위의 명령을 실한 시간이나 Author 정보가 다기 때문에 Hash 은 다를 것이다. 이어지는 내용에서 커
그에 사용하는 해시 을 위의 을 그대로 사용하지 자가 실해서 은 해시 을 사용해한다. 새로 생
git cat-file 명령으로 인해보자.
427
$ git cat-file -p fdf4fc3
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
author Scott Chacon <schacon@gmail.com> 1243040974 -0700
committer Scott Chacon <schacon@gmail.com> 1243040974 -0700
first commit
형식은 간하다. 해당 스냅샷에서 Tree(- 루트 디렉토리 같) 하나 가.
user.name user.email 정에서 가Author/Committer 정보, 시간 정보, 고 한 라인 운 다음 커
시지가 들어간다.
이제 커개 더 만들어 보자. 각 커는 이전 개를 가키도록 한다.
$ echo 'second commit' | git commit-tree 0155eb -p fdf4fc3
cac0cab538b970a37ea1e769cbbde608743bc96d
$ echo 'third commit' | git commit-tree 3c4e9c -p cac0cab
1a410efbd13591db07496601ebc7a059dd55cfe9
세 커는 각각 해당 스냅샷을 나타내는 Tree 를 하나키고 있다. 이상해 보이지만 우Git
히스토리를 만들었다. 마지SHA-1 을 주고 git log 명령을 실하면 아래와 같이 출력한다.
428
$ git log --stat 1a410e
commit 1a410efbd13591db07496601ebc7a059dd55cfe9
Author: Scott Chacon <schacon@gmail.com>
Date: Fri May 22 18:15:24 2009 -0700
Ê third commit
Êbak/test.txt | 1 +
Ê1 file changed, 1 insertion(+)
commit cac0cab538b970a37ea1e769cbbde608743bc96d
Author: Scott Chacon <schacon@gmail.com>
Date: Fri May 22 18:14:29 2009 -0700
Ê second commit
Ênew.txt | 1 +
Êtest.txt | 2 +-
Ê2 files changed, 2 insertions(+), 1 deletion(-)
commit fdf4fc3344e67ab068f836878b6c4951e3b15f3d
Author: Scott Chacon <schacon@gmail.com>
Date: Fri May 22 18:09:34 2009 -0700
Ê first commit
Êtest.txt | 1 +
Ê1 file changed, 1 insertion(+)
놀랍지 않은가! 금 우는 고수명령어 없이 저수의 명령으로만 Git 히스토리를 만들었다. 지금 한 일이 git add
git commit 명령을 실했을 때 Git 내부에서 일어나는 일이다. Git경된 일을 Blob 로 저하고
Index에 따라서 Tree 를 만든다. 고 이전 커체와 최상위 Tree 를 참고해서 커를 만든다.
Blob, Tree, Git의 주요 개이고 이 개는 전부 .git/objects 렉토리에 저된다. 이 예제에서
생성한 개아래와 같.
$ find .git/objects -type f
.git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2
.git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2
.git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1
.git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1
.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt
.git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1
429
내부의 포인터를 따라가면 아래와 같은 그이 그려.
그림 150. Git 저장소 내의 모든 개.
저장소
내용과 함더도 저한다고 기했다. Git이 개를 어떻게 저하는지부터 살펴보자. 화형 Ruby
이용하여 “what is up, doc?” 이라는 문자열을 저하는 방법내 내 .
irb 명령을 실하여 시작해보자.
$ irb
>> content = "what is up, doc?"
=> "what is up, doc?"
Git은 개의 타입을 Blob으로 만들면서 이를 시작으로 더를 만든다. 그 다음에 백 문자 하나, 내용의 크기, 마지
문자를 추가한다.
430
>> header = "blob #{content.length}\0"
=> "blob 16\u0000"
Git내용을 합SHA-1 을 계한다. Ruby에서도 require SHA1 라이를 가다가
수 있다. require 로 라이를 포함하고 나서 `Digest::SHA1.hexdigest()`를 호출한다.
>> store = header + content
=> "blob 16\u0000what is up, doc?"
>> require 'digest/sha1'
=> true
>> sha1 = Digest::SHA1.hexdigest(store)
=> "bd9dbf5aae1a3862dd1526723246b20206e5fc37"
이 내용을 git hash-object 명령을 실해보자. echo -n 명령에 -n 옵션을 사용한 이유는 입력을
전달할 때 개을 자동으로 지 않기 위함이다.
$ echo -n "what is up, doc?" | git hash-object --stdin
bd9dbf5aae1a3862dd1526723246b20206e5fc37
Git은 또 zlib으로 내용을 한다. Ruby에도 zlib 라이가 있으니 Ruby에서도 할 수 있다. 라이를 포함하고
`Zlib::Deflate.deflate()`를 호출한다.
>> require 'zlib'
=> true
>> zlib_content = Zlib::Deflate.deflate(store)
=> "x\x9CK\xCA\xC9OR04c(\xCFH,Q\xC8,V(-\xD0QH\xC9O\xB6\a\x00_\x1C\a\x9D"
마지으로 zlib으로 한 내용을 개로 저한다. SHA-1 중에서 에 있는 자를 가다 하위 디렉토리
이름으로 사용하고 나38자를 그 디렉토리 안에 있는 일이름으로 사용한다. Ruby에서는 FileUtils.mkdir_p
() 로 디렉토리(없으면) 만들고 File.open() 으로 일을 . 고 그 일에 zlib으로 한 내용을 write
() 함수로 저한다.
>> path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]
=> ".git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37"
>> require 'fileutils'
=> true
>> FileUtils.mkdir_p(File.dirname(path))
=> ".git/objects/bd"
>> File.open(path, 'w') { |f| f.write zlib_content }
=> 32
431
git cat-file 명령으로 저한 개의 내용을 인해보자.
---
$ git cat-file -p bd9dbf5aae1a3862dd1526723246b20206e5fc37
what is up, doc?
---
다 됐다. 이제 Git Blob 으로 만들었다.
Git 는 모방식으로 저하며 만 다. 더가 blob 니라 그commit 이나 tree 로 시작하게
되는 것뿐이다. Blob 는 여기서 보여것과 거의 지만 커이 개Tree 는 각기 다른 형식을 사용한다.
Git Refs
1a410e 이전의 모든 히스토리를 보려면 git log 1a410e 라고 실하면 히스토리를 볼 수 있지만, 여전히
1a410e 를 기한다. 이 커은 마지이기 때문에 히스토리를 따라 모든 개회할 수 있다. SHA-1
로 사용하기보다 운 이름으로 된 포인터가 있으면 그걸 사용하는 게 더 좋다. 외우기 운 이름으로 된 일에 SHA-1
을 저한다.
Git에서는 이런 것을 “References” 또는 “Refs” 라고 부른다. SHA-1 을 저하는 일은 .git/refs 렉토리
있다. 예제의 프로젝트에는 아직 .git/refs 렉토리 안일은 없고 디렉토리개 있다.
$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f
Refs가 있으면 커워진. 사실 내부는 아래처럼 순하다.
$ echo 1a410efbd13591db07496601ebc7a059dd55cfe9 > .git/refs/heads/master
SHA-1 대신에 지금 만든 Refs를 사용할 수 있다.
$ git log --pretty=oneline master
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
Refs 일을 접 고치는 것이 좀 못마하다. Git에는 좀 더 전하게 바수 있는 git update-ref 명령이 있다.
432
$ git update-ref refs/heads/master
1a410efbd13591db07496601ebc7a059dd55cfe9
Git 브랜치의 할이 바로 이거다. 브랜치는 어중 마지을 가키는 포인터 또는 Refs이다. 두 번째
을 가키는 브랜치를 만들어 보자.
$ git update-ref refs/heads/test cac0ca
브랜치는 접 가키는 커과 그 커으로 따라수 있는 모든 커을 포함한다.
$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
이제 Git 데이터이스는 아래 처럼 보인다.
그림 151. 브랜치 Refs가 추가된 Git 데이터이스.
git branch <branch> 명령을 실하면 Git은 내부적으로 update-ref 명령을 실한다. 입력브랜치 이름과
현 브랜치의 마지SHA-1 을 가update-ref 명령을 실한다.
HEAD
git branch <branch> 명령을 실할 때 Git은 어떻게 마지SHA-1 는 걸까? HEAD 일은
브랜치를 가키는 간접(symbolic) Refs.
433
간접 Refs라서 다른 것과 다. Refs는 다른 Refs를 가키는 것이라서 SHA-1 이 없다. 일을 열어 보면 아래와
이 생.
$ cat .git/HEAD
ref: refs/heads/master
git checkout test 를 실하면 GitHEAD 일을 아래와 같이 바.
$ cat .git/HEAD
ref: refs/heads/test
git commit 을 실하면 커가 만들어지는데, 지금 HEAD가 가키고 있던 커SHA-1 이 그 커
부모로 사용된다.
일도 으로 접 편할 수 있지만 git symbolic-ref 라는 명령어가 있어서 좀 더 전하게 사용할 수 있다.
명령으로 HEAD을 수 있다.
$ git symbolic-ref HEAD
refs/heads/master
HEAD경할 수도 있다.
$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test
refs 형식지 않으면 수정할 수 없다.
$ git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/
태그
중요한 개세 가지는 모살펴(Blob, Tree, ) 살펴볼 개가 하나가 았다. 그 개는 커체랑 매
하다. 처럼 , 그를 달았는지 시지는 무엇이고 어을 가키는지에 대한 정보가
포함된다. 그 개Tree 니라 커를 가키는 것이 그 둘의 이다. 브랜치처럼 커
키지만 수는 없다. 그 개는 늘 그 이름이 하는 커만 가.
Git의 기 에서 배그는 Annotated Lightweight 로 나. 아래와 같Lightweight
그를 만들어 보자.
434
$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d
Lightwieght 그는 만들기 쉽다. 브랜하지만 브랜치처럼 수는 없다. 이에 비해 Annotated 그는 좀 더
복잡하다. Annotated 그를 만들면 Git그 개를 만들고 거기에 커을 가키는 Refs를 저한다. Annotated
그는 커접 가키지 않고 그 개를 가. -a 옵션을 주고 Annotated 그를 만들어 인해보자.
$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag'
그 개SHA-1 인한다.
$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
git cat-file -p 명령으로 해당 SHA-1 의 내용을 회한다.
$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700
test tag
object 부분에 있는 SHA-1 이 실제로 그가 가키는 커이다. 뿐만 니라 모든 Git 그를 달 수
있다. 그를 다는 것이 니라 Git 그를 다는 것이다. Git을 개발하는 프로젝트에서는 관리자가
자신의 GPG 개키를 Blob 로 추가하고 그 일에 그를 달았다. 아래 명령으로 그 개키를 인할 수 있다.
$ git cat-file blob junio-gpg-pub
Linux Kernel 소에도 커다른 개를 가키는 그 개가 있다. 그는 저소에 처음으로 소스 코드를
포트했을 때 그 Tree 를 가.
리모트
모트 Refs라는 것도 있다. 모트를 추가하고 Push 하면 Git은 각 브랜치마다 Push 한 마지이 무엇인지
refs/remotes 렉토리에 저한다. 예를 들어, origin 이라는 모트를 추가하고 master 브랜치를 Push 한다.
435
$ git remote add origin git@github.com:schacon/simplegit-progit.git
$ git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To git@github.com:schacon/simplegit-progit.git
Ê a11bef0..ca82a6d master -> master
origin master 브랜치에서 서버마지으로 환한 커이 어것인지 refs/remotes/origin/master
일에서 인할 수 있다.
$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
refs/heads 에 있는 Refs브랜리 리모트 RefsCheckout 할 수 없고 기 용도로만 쓸 수 있는 브랜치인
것이다. 모트 Refs는 서버의 브랜치가 가키는 커이 무엇인지 적어마크이다.
Packfile
절의 예제대로 Git 명령을 실한 경우 test Git 소의 개데이터이스를 다시 살펴보면 개는 모11개로
Blob 4, Tree 3, 3, 1개가 된다.
$ find .git/objects -type f
.git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2
.git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2
.git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1
.git/objects/95/85191f37f7b0fb9444f35a9bf50de191beadc2 # tag
.git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1
.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt
.git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1
Gitzlib으로 일 내용을 하기 때문에 저장 공간이 많이 요하지 않다. 서 이 데이터이스에 저일은
925바이트에 되지 않는다. 크기가 큰 파일을 추가해서 이 기의 효과를 좀 더 살펴보자. 에서 사용했던 Grit
라이에 들어 있는 repo.rb 일을 추가한다. 일의 크기는 22K이다.
436
$ curl
https://raw.githubusercontent.com/mojombo/grit/master/lib/grit/repo.rb >
repo.rb
$ git checkout master
$ git add repo.rb
$ git commit -m 'added repo.rb'
[master 484a592] added repo.rb
Ê3 files changed, 709 insertions(+), 2 deletions(-)
Êdelete mode 100644 bak/test.txt
Êcreate mode 100644 repo.rb
Êrewrite test.txt (100%)
추가한 Tree 를 보면 repo.rb 일의 SHA-1 이 무엇인지 인할 수 있다.
$ git cat-file -p master^{tree}
100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
100644 blob 033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5 repo.rb
100644 blob e3f094f522629ae358806b17daf78246c27c007b test.txt
git cat-file 명령으로 개의 크기를 아래와 같인한다.
$ git cat-file -s 033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5
22044
일을 수정하면 어떻게 되는지 살펴보자.
$ echo '# testing' >> repo.rb
$ git commit -am 'modified repo a bit'
[master 2431da6] modified repo.rb a bit
Ê1 file changed, 1 insertion(+)
수정한 커Tree 인하면 로운 을 발할 수 있다.
$ git cat-file -p master^{tree}
100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
100644 blob b042a60ef7dff760008df33cee372b945b6e884e repo.rb
100644 blob e3f094f522629ae358806b17daf78246c27c007b test.txt
Blob 는 다른 개. Blob 400 라인 이후에 한 라인을 더 추가한 새 개이다. Git전히 새로운
Blob 를 만들어 저한다.
437
$ git cat-file -s b042a60ef7dff760008df33cee372b945b6e884e
22054
그럼 22K리 파일을 개 가지게 된다 (두 파일 각자도 하면 7K 사이즈). 거의 일을 개나 가지게 되는
것이 못마할 수도 있다. 처음 것과 두 번째 것 사이의 만 저할 수 없을까?
하다. Git이 처음 개를 저하는 형식“Loose이라고 부른다. 나중에 이 개일 하나로
(Pack)할 수 있다. 게 하여 간을 절하고 효율을 일 수 있다. GitLoose 무 많을 때, git gc 명령을
했을 때, 모트 서버로 Push할 때 이한다. git gc 명령을 실해서 어떻게 하는지 살펴보자.
$ git gc
Counting objects: 18, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (18/18), done.
Total 18 (delta 3), reused 0 (delta 0)
objects 렉토리를 열어보면 개대부분이 사라고 한 일이 새로 생.
$ find .git/objects -type f
.git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
.git/objects/info/packs
.git/objects/pack/pack-978e03944f5c581011e6998cd0e9e30000905586.idx
.git/objects/pack/pack-978e03944f5c581011e6998cd0e9e30000905586.pack
되지 않은 Blob 는 어도 가키지 않는 개. , “what is up, doc?” “test content” 예제에서
만들었던 개이다. 에도 추가있지 않으면 이 개dangling 되고 Packfile에 추가되지
않는다.
새로 생긴 파일은 Packfile과 그 Index이다. 일 시스에서 제된 개가 전부 이 Packfile에 저된다. Index 일에
대해서는 빠르을 수 있도록 Packfile에 오프이 들어 있다. gc 명령을 실하기 전에 있던 일 크기는 15K
정도였었는데 새로 만들어Packfile7K과하다. 이다. 하여 디스크 사용정도로
었다.
이런 일은 어떤 식으로 처하는 것인가? 시키면 Git저 이름이나 크기가 비일을 는다.
일을 비해서 한 일은 다른 부분만 저한다. Git마나 간을 절해 주는지 Packfile을 열어 인할 수 있다.
git verify-pack 명령어는 한 내용을 보여.
438
$ git verify-pack -v .git/objects/pack/pack-
978e03944f5c581011e6998cd0e9e30000905586.idx
2431da676938450a4d72e260db3bf7b0f587bbc1 commit 223 155 12
69bcdaff5328278ab1c0812ce0e07fa7d26a96d7 commit 214 152 167
80d02664cb23ed55b226516648c7ad5d0a3deb90 commit 214 145 319
43168a18b7613d1281e5560855a83eb8fde3d687 commit 213 146 464
092917823486a802e94d727c820a9024e14a1fc2 commit 214 146 610
702470739ce72005e2edff522fde85d52a65df9b commit 165 118 756
d368d0ac0678cbe6cce505be58126d3526706e54 tag 130 122 874
fe879577cb8cffcdf25441725141e310dd7d239b tree 136 136 996
d8329fc1cc938780ffdd9f94e0d364e0ea74f579 tree 36 46 1132
deef2e1b793907545e50a2ea2ddb5ba6c58c4506 tree 136 136 1178
d982c7cb2c2a972ee391a85da481fc1f9127a01d tree 6 17 1314 1 \
Ê deef2e1b793907545e50a2ea2ddb5ba6c58c4506
3c4e9cd789d88d8d89c1073707c3585e41b0e614 tree 8 19 1331 1 \
Ê deef2e1b793907545e50a2ea2ddb5ba6c58c4506
0155eb4229851634a0f03eb265b69f5a2d56f341 tree 71 76 1350
83baae61804e65cc73a7201a7252750c76066a30 blob 10 19 1426
fa49b077972391ad58037050f2a75f74e3671e92 blob 9 18 1445
b042a60ef7dff760008df33cee372b945b6e884e blob 22054 5799 1463
033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5 blob 9 20 7262 1 \
Ê b042a60ef7dff760008df33cee372b945b6e884e
1f7a7a472abf3dd9643fd615f6da379c4acb3e3a blob 10 19 7282
non delta: 15 objects
chain length = 1: 3 objects
.git/objects/pack/pack-978e03944f5c581011e6998cd0e9e30000905586.pack: ok
033b4 Blob이 처음 추가한 repo.rb 일인데, Blob두 번째 버전인 b042a Blob을 가. 과에서 세 번째
럼은 된 개의 크기를 나타. b042a 의 크기는 22K지만 `033b4`9바이트된다. 특이한
을 그대로 저하는 것이 번째니라 두 번째 버전이라는 것이다. 번째 버전은 만 저된다.
버전에 접할 때가 더 많고 신 버전에 접하는 속도가 더 하기 때문에 이게 한다.
제나 다시 할 수 있기 때문에 이 기은 정판타스하다. Git은 가자동으로 데이터이스를 재해서
간을 절한다. git gc 명령으로 할 수도 있다.
Refspec
브랜Refs를 간하는 것은 많이 . 은 실은 좀 더 복잡하다. 서 자주 해왔Git
소를 새로 생성하고 사용을 하다가 origin 이라는 모트 저소를 새로 추가 은 지정하려면 아래처럼 실한다.
$ git remote add origin https://github.com/schacon/simplegit-progit
이 명령은 origin 이라는 저소 이름, URL, Fetch Refspec.git/config 일에 추가한다.
439
[remote "origin"]
Ê url = https://github.com/schacon/simplegit-progit
Ê fetch = +refs/heads/*:refs/remotes/origin/*
Refspec 형식+ <src>:<dest> 있다. + 는 생하고, <src> 모트 저소의 Refs 이고
<dst> 되는 로소의 Refs 이다. + Fast-forward데이트를 용하는 것이다.
적으로 Gitgit remote add 명령으로 생성한 정을 참고하여 모트 서버에서 refs/heads/ 에 있는
Refs를 가다 로refs/remotes/origin/ 에 기록한다. 에서 서버에 있는 master 브랜치에 접할 때는
아래와 같이 한다.
$ git log origin/master
$ git log remotes/origin/master
$ git log refs/remotes/origin/master
이 세 명령의 과가 모두 같. Git은 모refs/remotes/origin/master 라고 해한다.
master 브랜치만 가져올 수 있게 하려면 fetch 부분을 아래와 같이 바. 그러면 다른 브랜치는 가져올 수 없다.
fetch = +refs/heads/master:refs/remotes/origin/master
이는 해당 모트 저소에서 git fetch 명령을 실할 때 자동으로 사용되는 Refspec이다. 다른 Refspec
오려면 명령의 아규먼트로 넘. 모트 브랜master 를 로컬 브랜origin/mymaster 로 가오려면
아래와 같이 실한다.
$ git fetch origin master:refs/remotes/origin/mymaster
Refspec을 여러 개 넘도 된다. 꺼번브랜치를 여러 개 가온다.
$ git fetch origin master:refs/remotes/origin/mymaster \
Ê topic:refs/remotes/origin/topic
From git@github.com:schacon/simplegit
Ê! [rejected] master -> origin/mymaster (non fast forward)
Ê* [new branch] topic -> origin/topic
여기서 master 브랜치는 Fast-forward니라서 거절된다. 하지만, Refspec + 를 추가하면 제로 .
일에도 Refspec을 여러 개 적을 수 있다. master experiment 브랜치를 둘 다 적으면 origin 모트에서
상 함온다.
440
[remote "origin"]
Ê url = https://github.com/schacon/simplegit-progit
Ê fetch = +refs/heads/master:refs/remotes/origin/master
Ê fetch = +refs/heads/experiment:refs/remotes/origin/experiment
하지만, Glob 은 사용할 수 없다.
fetch = +refs/heads/qa*:refs/remotes/origin/qa*
그 대신 네임이스 형식(렉토리 형식)으로는 사용할 수 있다. QA 팀이 Push 하는 브랜치가 있고 이 브랜치를
오고 으면 아래와 같정한다. 다음은 master 브랜QA 팀의 브랜치만 가오는 정이다.
[remote "origin"]
Ê url = https://github.com/schacon/simplegit-progit
Ê fetch = +refs/heads/master:refs/remotes/origin/master
Ê fetch = +refs/heads/qa/*:refs/remotes/origin/qa/*
좀 더 복잡한 것도 가하다. QA 팀뿐만 니라, 개발자, 합 팀 등이 사용하는 브랜치를 네임이스 분해
놓으면 좀 더 Git을 편하게 사용할 수 있다.
Refspec Push 하기
와 같방식으로 네임이스를 사용하여 모트 브랜치를 구별하여 사용하는 것은 괜찮방법이다. QA팀이
네임이스를 사용하지 않는 브랜치를 모트에 네임이스를 써서 Push 하려면 어떻게 해할까?
Refspec으로 가하다.
QA 팀이 master 브랜치를 모트 저소에 qa/master Push 하려면 아래와 같이 한다.
$ git push origin master:refs/heads/qa/master
git push origin 을 실할 때마다 Git이 자동으로 Push 하게 하려면 아래와 같일에 push 목을
추가한다.
[remote "origin"]
Ê url = https://github.com/schacon/simplegit-progit
Ê fetch = +refs/heads/*:refs/remotes/origin/*
Ê push = refs/heads/master:refs/heads/qa/master
다시 하자면 위와 같정은 git push origin 을 실할 때 로컬 브랜master 모트 브랜qa/master
Push 하도록 하는 정이다.
441
Refs 삭제하기
Refspec으로 서버에 있는 Refs제할 수 있다.
$ git push origin :topic
Refspec형식<src>:<dst> 이니까 <src> 를 비우고 실하면 <dst> 를 비우라는 명령이 된다. 따라서 위
명령은 모트의 topic 브랜치를 제한다.
다음과 은 명령으로도 브랜치를 제할 수 있다. Git 버전 v1.7 이상에서 가하다.
$ git push origin --delete topic
데이터 전프로토콜
Git에서 데이터를 전송할 때 보통 두 가지 의 프로토콜을 사용한다. 하나는 “dumb프로토콜이고 다른
스마트프로토콜이다. 프로토콜Git이 어떻게 데이터를 전송하는지 살펴.
Dumb 프로토콜
기전용으로만 사용하는 HTTP 소를 Clone 하거나 Fetch 할 때가 Dumb 프로토콜을 사용하는 때이다. Dumb
프로토콜이라 부는 이유는 서버가 데이터를 전송할 때 Git된 어도 전사용하지 않기 때문이다.
Fetch 과정은 HTTP GET 을 여러 뿐이다. 이때 라이트는 서버의 Git 아웃이 특하지 않다고
가정한다.
Dumb 프로토콜을 사용하는 경우가 드. Dumb 프로토콜을 사용하면 데이터 전송을
게 하기 어려서 비개용 저소의 데이터를 전송하기에 적합하지 않다. 이후에 명할
스마트 프로토콜을 사용하도록 조언하는 바이다.
simplegit 라이에 대한 http-fetch 과정을 살펴보자.
$ git clone http://server/simplegit-progit.git
info/refs 일을 내려는다. 일은 update-server-info 명령으로 작성되기 때문에 post-receive
에서 update-server-info 명령을 호출해HTTP를 사용할 수 있다.
=> GET info/refs
ca82a6dff817ec66f44342007202690a93763949 refs/heads/master
모트 RefsSHA-1 이 든 목록을 가왔고 다음은 HEAD Refs는다. HEAD Refs 에 데이터를 내려
나서 어RefsCheckout 할 지 알게 된다.
442
=> GET HEAD
ref: refs/heads/master
데이터 전송을 마치면 master 브랜치를 Checkout 한다. 지금은 아직 전송을 시작하는 시이다. info/refs
ca82a6 에서 시작해한다고 나있다. 서 그 커을 기으로 Fetch 한다.
=> GET objects/ca/82a6dff817ec66f44342007202690a93763949
(179 bytes of binary data)
서버에 Loose 으로 있기 때문에 HTTP 서버에서 정적 일을 가이 개를 가오면 된다.
서버로부터 어온 개zlibHeader어 내면 아래와 같은 모습이 된다.
$ git cat-file -p ca82a6dff817ec66f44342007202690a93763949
tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
author Scott Chacon <schacon@gmail.com> 1205815931 -0700
committer Scott Chacon <schacon@gmail.com> 1240030591 -0700
changed the version number
아직 개 더 내려받아야 한다. cfda3b 금 내려은 커Tree 이고, 085bb3 는 부모 커
이다.
=> GET objects/08/5bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
(179 bytes of data)
는 내려았다. 하지만, Tree 를 내려으려고 하니 아래와 같은 오가 발생한다.
=> GET objects/cf/da3bf379e4f8dba8717dee55aab78aef7f4daf
(404 - Not Found)
이런! 존재하지 않는다는 404 시지가 . 해당 Tree 가 서버에 Loose 으로 저장돼 있지 않을 수 있다. 해당
가 다른 저소에 있거나 저소의 Packfile 속에 들어 있을 때 그. Git은 다른 저소 목록에서 는다.
=> GET objects/info/http-alternates
(empty file)
다른 저소 목록에 없으면 GitPackfile에서 해당 개는다. 게 하면 프로젝트를 Fork 해도 디스크 간을
효율적으로 사용할 수 있다. 서버에서 은 다른 저소 목록에는 없어서 개실히 Packfile 속에 있다.
Packfile이 있는지는 objects/info/packs 일에 들어 있다. 일도 update-server-info 명령이
443
생성한다.
=> GET objects/info/packs
P pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
서버에는 Packfile이 하나 있다. 는 이 일 속에 있다. 이 개가 있는지 PackfileIndex(Packfile이 포함하는
일의 목록)에서 는다. 서버에 Packfile이 여러 개 있으면 이런 으로 개가 어Packfile에 있는지 는다.
=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.idx
(4k of binary data)
이제 PackfileIndex를 가져와서 개가 있는지 인한다. Packfile Index에서 해당 개SHA-1 과 오프
한다. 았으면 해당 Packfile을 내려는다.
=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
(13k of binary data)
Tree 어 오고 나면 커데이터를 가온다. 마도 금 내려Packfile 속에 모든 커데이터가 들어 있을
것이다. 서버에 더는 전송 요을 보내지 않는다. 나면 GitHEAD가 가키는 master 브랜치의 소스코드를
원해놓는다.
스마트 프로토콜
Dumb 프로토콜순하다는 장점이 있으나 데이터를 효율적으로 전송할 수 없다. 스마트 프로토콜로 데이터를
전송하는 것이 더 일적이다. 이 프로토콜모트 서버에서 처할 작이 있다. 서버는 라이트가 어
데이터를 고 있고 어데이터가 요한지 분하여 실제로 전송할 데이터를 추려. 서버가 할 일을 가지 일로
분할 수 있는데 데이터를 로드할 때 하는 일과 다운로드할 때 하는 일이 다.
데이터 업로드
모트 서버로 데이터를 로드하는 과정은 send-pack receive-pack 과정으로 나수 있다. 라이트에서
되는 send-pack 과 서버의 receive-pack 은 서로 연결된다.
SSH
origin URLSSH URL인 상에서 git push origin master 명령을 실하면 Gitsend-pack
시작한다. 이 과정에서는 SSH 연결을 만들고 이 SSH 연결해서 아래와 같은 명령어를 실한다.
444
$ ssh -x git@server "git-receive-pack 'simplegit-progit.git'"
00a5ca82a6dff817ec66f4437202690a93763949 refs/heads/masterreport-status \
Ê delete-refs side-band-64k quiet ofs-delta \
Ê agent=git/2:2.1.1+github-607-gfba4028 delete-refs
0000
git-receive-pack 명령은 Refs 정보를 한 라인에 하나보여. 번째 라인에는 master 브랜치의 이름과
SHA-1 을 보여주는데 여기에 서버의 Capability도 함보여(여기서는 report-status, delete-refs,
기타 등등과 라이Identifier시한다).
각 라인의 처음은 4 바이트는 에 이어지는 나지 데이터의 이를 나타. 라인을 보자. 00a5로 시작하는데
10수로 165를 나타. 의 처음 4 바이트를 제외한 나이가 165 바이트라는 이다. 마지라인은
0000이다. 이는 서버가 Refs 목록의 출력을 끝냈다는 것을 의한다.
서버에 가 있는지 알기 때문에 이제 서버에 없는 커이 무엇인지 알 수 있다. Push Refs에 대한 정보는 send-pack
과정에서 서버의 receive-pack 과정으로 전달된다. 예를 들어 master 브랜치를 데이트하고 experiment
브랜치를 추가할 때는 아래와 같은 정보를 서버에 보.
0076ca82a6dff817ec66f44342007202690a93763949
15027957951b64cf874c3557a0f3547bd83b3ff6 \
Ê refs/heads/master report-status
006c0000000000000000000000000000000000000000
cdfdb42577e2506715f8cfeacdbabc092bf63e8d \
Ê refs/heads/experiment
0000
Git은 예전 SHA-1, SHA-1, Refs 이름을 한 담아 전송한다. 라인에는 라이Capability도 포함된다.
SHA-1 이 모'0’인 것은 없음()을 의한다. experiment Refs는 새로 추가하는 것이라서 왼쪽 SHA-1이 모
0이다. 대로 오른SHA-1 이 모'0’이면 Refs제한다는 의.
그다음에 서버에 없는 객체를 전부 하나의 Packfile담아 전송한다. 마지에 서버는 성했거나 실했다고 응답한다.
000eunpack ok
HTTP(S)
HTTP해 데이터를 로드하는 과정도 크게 다지 않지만 처음 과정만 간 다. 선 아래와 같
으로 시작한다.
445
=> GET http://server/simplegit-progit.git/info/refs?service=git-receive-
pack
001f# service=git-receive-pack
00ab6c5f0e45abd7832bf23074a333f739977c9e8188 refs/heads/masterreport-
status \
Ê delete-refs side-band-64k quiet ofs-delta \
Ê agent=git/2:2.1.1~vmg-bitmaps-bugaloo-608-g116744e
0000
번째 클라이트 요과 서버의 응답이다. 이어지는 라이트 요POST 소드를 써서 send-pack 명령이
하는 데이터를 서버로 전송하는 요이다.
=> POST http://server/simplegit-progit.git/git-receive-pack
POST send-pack Packfile을 데이터로 전송한다. 전송한 데이터가 서버에서 처과가 HTTP
응답으로 전달된다.
데이터 다로드
데이터를 다운로드하는 것는 fetch-pack upload-pack 과정으로 나. 라이트가 fetch-pack
시작하면 서버의 upload-pack 연결되고 서로 어데이터를 내려을지 정한다.
SSH
SSH 프로토콜을 사용하면 fetch-pack 아래와 같이 실한다.
$ ssh -x git@server "git-upload-pack 'simplegit-progit.git'"
fetch-pack 연결upload-pack 아래와 같은 데이터를 전송한다.
00dfca82a6dff817ec66f44342007202690a93763949 HEADmulti_ack thin-pack \
Ê side-band side-band-64k ofs-delta shallow no-progress include-tag \
Ê multi_ack_detailed symref=HEAD:refs/heads/master \
Ê agent=git/2:2.1.1+github-607-gfba4028
003fe2409a098dc3e53539a9028a94b6224db9d6a6b6 refs/heads/master
0000
receive-pack 응답우 비하지만, Capability 부분은 다. HEAD Refs
(symref=HEAD:refs/heads/master)도 알려주기 때문에 저소를 Clone 하면 무엇을 Checkout 할지 .
fetch-pack 은 이 정보를 살펴보고 이가지는 개에는 “have” 이고 내려받아야 하는 개“want”
정보를 만든다. 마지라인에 “done” 이라고 적어서 보내면 서버의 upload-pack 은 해당 데이터를 Packfile
446
만들어 전송한다.
003cwant ca82a6dff817ec66f44342007202690a93763949 ofs-delta
0032have 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
0009done
0000
HTTP(S)
HTTPFetch 하는 과정은 개의 HTTP 으로 이루어. 번째 GET 으로 응답 과는 SSH에서
내용과 .
=> GET $GIT_URL/info/refs?service=git-upload-pack
001e# service=git-upload-pack
00e7ca82a6dff817ec66f44342007202690a93763949 HEADmulti_ack thin-pack \
Ê side-band side-band-64k ofs-delta shallow no-progress include-tag \
Ê multi_ack_detailed no-done symref=HEAD:refs/heads/master \
Ê agent=git/2:2.1.1+github-607-gfba4028
003fca82a6dff817ec66f44342007202690a93763949 refs/heads/master
0000
과는 SSH 연결을 사용할 때 git-upload-pack 명령을 실한 것과 비하지만 이어지는 두 번째 이 다.
=> POST $GIT_URL/git-upload-pack HTTP/1.0
0032want 0a53e9ddeaddad63ad106860237bbf53411d11a7
0032have 441b40d833fdfa93eb2908e52742248faf0ee993
0000
전송할 내용은 에서 살펴것과 . 전송한 데이터를 서버에서 처과가 HTTP 응답으로 전달되고 과에 따라
Packfile이 포함되어 있을 수 있다.
프로토콜 요약
절을 Git이 사용하는 데이터 전송 프로토콜을 간하게 살펴보았다. Git이 사용하는 데이터 전송 프로토콜에는
multi_ack side-band 은 추가적인 많은 기도 포함하고 있지만, 이 책에서 다수 없어 명하지는 않는다.
책의 내용은 Git이 어떻게 라이서버 간에 데이터를 주고는지 기적인 느을 전달하기 위해 노력한다. 데이터
전송 프로토콜의 많은 기을 활용해보고 다면 Git 소스코드를 살펴보는 것이 좋다.
운영 및 데이터 복구
가는 저소를 수 정지도 모른다. 소를 좀 더 알(Compact) 만들고, 다른 VCS에서
포트하고 나서 그 재를 치운다든가, 니면 문제가 생복구할 수도 있다. 이 절은 이요한 것을
명한다.
447
운영
Git은 때가 되면 자동으로 “auto gc” 명령을 실한다. 이 명령이 실되는 경우 대부분은 무런 일도 일어나지 않는다.
Loose 무 많거나, Packfile 무 많으면 Git은 그제야 진git gc 명령이 일하게 한다. gc 명령은
GarbageCollect 하는 명령이다. 이 명령은 Loose 를 모Packfile에 저하거나 작은 Packfile을 모
하나의 Packfile에 저한다. 무런 커도 가키지 않는 개가 있고 오랫동() 무도 쓰지 않는다면
제한다.
GitGarbageCollect 할 지 지 자동으로 판해서 처하도록 아래와 같gc 명령을 실할 수 있다.
$ git gc --auto
이 명령을 실해도 보무 일도 일어나지 않는다. Loose 7천 개가 넘거나 Packfile50개가 넘지 않으면
Git은 실제로 gc 을 실하지 않는다. 원한다면 gc.auto gc.autopacklimit 정으로 그 자를 절할 수
있다.
gc 명령이 하는 일 중 하나는 Refs일 하나로 하는 일이다. 예를 들어 저소에 아래와 같브랜와 태그가
있다고 하자.
$ find .git/refs -type f
.git/refs/heads/experiment
.git/refs/heads/master
.git/refs/tags/v1.0
.git/refs/tags/v1.1
git gc 를 실하면 refs 에 있는 일은 사라. 대신 Git은 그 일을 .git/packed-refs 일로 해서
효율을 인다.
$ cat .git/packed-refs
# pack-refs with: peeled fully-peeled
cac0cab538b970a37ea1e769cbbde608743bc96d refs/heads/experiment
ab1afef80fac8e34258ff41fc1b867c702daa24b refs/heads/master
cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0
9585191f37f7b0fb9444f35a9bf50de191beadc2 refs/tags/v1.1
^1a410efbd13591db07496601ebc7a059dd55cfe9
이 상에서 Refs를 수정하면 일을 수정하는 게 니라 refs/heads 더에 일을 새로 만든다. GitRefs
키는 SHA-1 을 때 refs 렉토리에서 고 없으면 packed-refs 일에서 는다. 그러니까 어
Refs가 있는데 refs 렉토리에서 못 으면 packed-refs 에 있을 것이다.
마지에 있는 `^`로 시작하는 라인을 살펴보자. 이것은 바로 그가 Annotated 그라는 것을 . 해당
그가 가키는 커이라는 이다.
448
데이터 복구
Git을 사용하다 보면 커어 버는 실수를 할 때도 있다. 중인 브랜치를 제로 제하거나,
브랜으로 어 내버렸거나, 제로(Hard) Reset 하면 그게 될 수 있다. 든 원치 않게 커어 버
어떻게 다시 찾아야 할까?
master 브랜치에서 제로(Hard) Reset 한 경우를 예로 들어 어버복구해보자. 습용 저소를
만든다.
$ git log --pretty=oneline
ab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit
484a59275031909e19aadb7c92262719cfcdf19a added repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
master 브랜치를 예전 커으로 Reset 한다.
$ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9
HEAD is now at 1a410ef third commit
$ git log --pretty=oneline
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
최근 밋 두 개는 어떤 브랜치도 가키지 않는다. 어 버렸다고 볼 수 있다. 브랜치에 다시 포함하려면
마지을 다시 찾아야 한다. SHA-1 을 외도 없고 찾아방법요하다.
git reflog 명령을 사용하는 게 가쉽다. HEAD가 가키는 커이 바때마다 Git자동으로 그
이 무엇인지 기록한다. 새로 커하거나 브랜치를 바Reflog도 늘어난다. Git Refs 절에서 배운 git update-
ref 명령으로도 Reflog남길 수 있다. 이런 상을 대비할 수 있다는 git update-ref 사용해하는
이유 중 하나다. git reflog 명령만 실하면 제나 발자돌아볼 수 있다.
$ git reflog
1a410ef HEAD@{0}: reset: moving to 1a410ef
ab1afef HEAD@{1}: commit: modified repo.rb a bit
484a592 HEAD@{2}: commit: added repo.rb
reflog 명령으로 인해보니 Checkout 했었던 커밋 두 개만 보여 . 구체적인 정보까지 보여주않는다. 좀 더
자세히 보려면 git log -g 명령을 사용해한다. 이 명령은 Refloglog 명령 형식으로 보여.
449
$ git log -g
commit 1a410efbd13591db07496601ebc7a059dd55cfe9
Reflog: HEAD@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date: Fri May 22 18:22:37 2009 -0700
Ê third commit
commit ab1afef80fac8e34258ff41fc1b867c702daa24b
Reflog: HEAD@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date: Fri May 22 18:15:24 2009 -0700
Ê modified repo.rb a bit
두 번째 어버것이니까 그 커을 가키는 브랜치를 만들어 복구한다. 그 커(ab1afef)을 가키는 브랜
recover-branch 를 만든다.
$ git branch recover-branch ab1afef
$ git log --pretty=oneline recover-branch
ab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit
484a59275031909e19aadb7c92262719cfcdf19a added repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
master 브랜치가 가키던 커recover-branch 브랜치가 가키게 했다. 이 커밋 두 개는 다시 도달할 수 있다.
이보다 좋은 상을 가정해보자. 어 버린 두 Reflog에서 못 았다. recover-branch 를 다시 제하고
Reflog제하여 이 상을 재하자. 그러면 그 은 다시 도달할 수 없게 된다.
$ git branch -D recover-branch
$ rm -Rf .git/logs/
Reflog 데이터는 .git/logs/ 렉토리에 있기 때문에 그 디렉토리를 지우면 Reflog도 다 지워진. 그러면 커
어떻게 복구할 수 있을까? 한 가지 방법이 있는데 git fsck 명령으로 데이터이스의 Integrity사할 수 있다.
명령에 --full 옵션을 주고 실하면 길 잃은 개를 모보여.
450
$ git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (18/18), done.
dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4
dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b
dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9
dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293
Dangling 어버이니까 그 SHA-1를 가키는 브랜치를 만들어 복구할 수 있다.
삭제
Git장점우 많다. 물론 단점도 있는데 Clone 할 때 히스토리를 전부 내려는 것이 문제가 될 때가 있을 수 있다.
Git은 모든 일의 모든 버전을 내려는다. 사실 일이 모소스코드라면 무 문제 없다. Git해서
데이터를 한다. 하지만, 바이너리 파일을 어버Clone 할 때마다 그 일을 내려는다. 다음
에서 그 일을 제해도 히스토리에는 그대로 남아 있기 때문에 Clone 할 때마다 포함된다.
이 문제는 Subversion이나 Perforce 소를 Git으로 환할 때 문제가 된다. Subversion이나 Perforce 시스
히스토리를 내려는 것이 로 해당 일이 여러 추가될 수 있다. 은 다른 VCS에서 Git 소로
포트하려고 하는데 Git 소의 간이 분하지 않으면 찾아제해한다.
주의: 이 작업을 하다가 커밋 히스토리를 망쳐버릴 수 . 제하거나 수정할 일이 들어 있는 커이후에 추가된
은 모재작성된다. 프로젝트를 포트 하자마자 하는 것은 괜찮. 아직 아무도 새 저소를 가지고 일하지 않기
때문이다. 그게 니면 히스토리Rebase 한다고 관련된 사람 모에게 알려한다.
시나오 하나를 살펴보자. 저 저소에 크기가 큰 파일을 고 다음 커에서는 제할 것이다. 고 나서 그 일을
다시 찾아 소에서 제한다. 저 히스토리에 크기가 를 추가한다.
$ curl https://www.kernel.org/pub/software/scm/git/git-2.1.0.tar.gz >
git.tgz
$ git add git.tgz
$ git commit -m 'add git tarball'
[master 7b30847] add git tarball
Ê1 file changed, 0 insertions(+), 0 deletions(-)
Êcreate mode 100644 git.tgz
이런 tar 일을 버전관리 하자고 을 수는 없다. 다음 커에서 다시 제한다.
$ git rm git.tgz
rm 'git.tgz'
$ git commit -m 'oops - removed large tarball'
[master dadf725] oops - removed large tarball
Ê1 file changed, 0 insertions(+), 0 deletions(-)
Êdelete mode 100644 git.tgz
451
gc 명령으로 하고 나서 저소 크기가 마나 되는지 인한다.
$ git gc
Counting objects: 17, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (13/13), done.
Writing objects: 100% (17/17), done.
Total 17 (delta 1), reused 10 (delta 0)
count-objects 명령은 사용하는 용마나 되는지 알려.
$ git count-objects -v
count: 7
size: 32
in-pack: 17
packs: 1
size-pack: 4868
prune-packable: 0
garbage: 0
size-garbage: 0
size-pack 목의 자가 Packfile의 크기다. 위가 로바이트라서 이 Packfile의 크기는 5MB이다. 큰 파일을
하기 전에는 2K였다. 요없는 일을 지우고 커했지만 히스토리에서 제되지 않았다. 큰 파일이 하나
들어 있기 때문에 무 작은 프로젝트인데도 Clone 하는 사람마다 5MB씩 필요하다. 이제 그 일을 제해 보자.
일을 는다. , 지금은 무일인지 이알고 있지만 모른다고 가정한다. 떤 파일이 용지 어떻게
찾아? 게다가 git gc 를 실됐으면 전부 Packfile 에 있어서 더 기 어렵다. Plumbing 명령어 git verify-
pack 일과 그 크기 정보를 수하고 세 번째 필드를 기으로 그 과를 정한다. 번째 필드가 일 크기다.
큰 파개만 제할 것이기 때문에 tail 명령으로 가장 큰 파3개만 .
$ git verify-pack -v .git/objects/pack/pack-29…69.idx \
Ê | sort -k 3 -n \
Ê | tail -3
dadf7258d699da2c8d89b09ef6670edb7d5f91b4 commit 229 159 12
033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5 blob 22044 5792 4977696
82c99a3e86bb1267b236a4b6eff7868d97489af1 blob 4975916 4976258 1438
마지에 있는 개5MB로 가크다. 이제 그 일이 정히 무일인지 알한다. 밋 메시지 규칙 만들기
에서 소개했던 rev-list 명령에 --objects 옵션을 추가하면 커SHA Blob 일이름, SHA-1
보여. 과에서 해당 Blob의 이름을 는다.
$ git rev-list --objects --all | grep 82c99a3
82c99a3e86bb1267b236a4b6eff7868d97489af1 git.tgz
452
히스토리에 있는 모든 Tree 에서 이 일을 제한다. 저 이 일을 추가한 커는다.
$ git log --oneline --branches -- git.tgz
dadf725 oops - removed large tarball
7b30847 add git tarball
일을 히스토리에서 전히 제하면 6df76 이후 커은 모재작성된다. 히스토리 단장하기 에서 배운 filter-
branch 명령으로 제한다.
$ git filter-branch --index-filter \
Ê 'git rm --ignore-unmatch --cached git.tgz' -- 7b30847^..
Rewrite 7b30847d080183a1ab7d18fb202473b3096e9f34 (1/2)rm 'git.tgz'
Rewrite dadf7258d699da2c8d89b09ef6670edb7d5f91b4 (2/2)
Ref 'refs/heads/master' was rewritten
--index-filter 옵션히스토리 단장하기 에서 배운 --tree-filter 하다. --tree-filter
디스크에 Checkout 해서 일을 수정하지만 --index-filter Staging Area에서 수정한다.
제도 rm file 명령이 니라 git rm --cached 명령으로 제한다. 디스크에서 제하는 것이 니라 Index에서
제하는 것이다. 게 하는 이유는 속도가 빠르기 때문이다. Filter를 실할 때마다 각 비전을 디스크에 Checkout
하지 않기 때문에 이것이 트라 캡숑 빠르. --tree-filter 로도 은 작을 할 수 있다. 지 느뿐이다.
git rm 명령에 --ignore-unmatch 옵션을 주면 일이 없는 경우에 에러를 출력하지 않는다. 마지으로
문제가 생것은 7b30847 부터라서 filter-branch 명령에 7b30847 부터 재작성하라고 알려한다.
지 않으면 부터 시작해서 불필요한 것까지 재작성해 버.
히스토리에서는 더는 그 일을 가키지 않는다. 하지만, Reflogfilter-branch를 실할 때 생기는 Refs남아있다.
filter-branch .git/refs/original 렉토리에 실될 때의 상를 저한다. 서 이 일도 제하고
데이터이스를 다시 한다. 하기 전에 해당 개를 가키는 Refs는 모한다.
$ rm -Rf .git/refs/original
$ rm -Rf .git/logs/
$ git gc
Counting objects: 15, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (15/15), done.
Total 15 (delta 1), reused 12 (delta 0)
간이 마나 절됐는지 인한다.
453
$ git count-objects -v
count: 11
size: 4904
in-pack: 15
packs: 1
size-pack: 8
prune-packable: 0
garbage: 0
size-garbage: 0
된 저소의 크기는 8K로 내려. 5MB보다 한참 작다. 하지만, size 목은 아직 되지 않는 Loose
크기를 나타내는데 그 목이 아직 크다. , 아직 전히 제거된 것은 니다. 하지만, 이 개Push 할 수도 Clone
수도 없다. 이 중요하다. 전히 제하려면 git prune --expire 명령으로 제해한다.
$ git prune --expire now
$ git count-objects -v
count: 0
size: 0
in-pack: 15
packs: 1
size-pack: 8
prune-packable: 0
garbage: 0
size-garbage: 0
환경변수
Git은 늘 bash 환경 에서 동작한다. 환경수에 따라 Git의 동작이 달라. Git에 영을 주는 환경수가 어
것들이 있고 또 그 에 따라 Git이 어떻게 동작하는지 알아두쓸모 있다. Git관련된 환경수 전를 다루지는
못하지만 알아두면 유용한 수들은 거의 다 다.
Git영향을 주는 변수
Git의 여러 기중 일적인 기이 동작할 때 영치는 주요 환경수는 아래와 같.
*GIT_EXEC_PATH * 수는 Git의 여러 Subprogram(예를 들어 git-commit, git-diff 은 것들)이 어디에
있는지를 정한다. 정을 인하려면 git --exec-path 명령을 실한다.
*HOME * 수는 일적으로 경하지 않는 수이다. 주 많은 프로그이 이 수를 참하기 때문이다. Git이 이
수에 영는 부분은 사용자(User) 에 영을 주는 Git 환경일을 을 때이다. Git을 포터
치하거나 해서 사용자 환경일의 위치를 제로 지정해하면 Git을 실하는 HOME 수에 원하는
정한다.
*PREFIX * 수도 비한 성으로 사용자 수시스의 환경일을 을 위치를 정한다. Git
을 위치는 $PREFIX/etc/gitconfig 이다.
454
*GIT_CONFIG_NOSYSTEM * 수를 정하면 시스의 환경일을 적용하지 않는다. 수는 시스
의 환경일이 자해되는데 고한이 없는 경우 정하면 유용하다.
*GIT_PAGER * 수는 Git면에 출력할 내용이 한 면이 넘어때 사용할 프로그정한다. 수에
정하지 않으면 PAGER 수의 내용도 참고한다.
*GIT_EDITOR * 수는 커내용을 입력하는 상Git이 사용자로부터 어내용을 입력는 경우 실
기를 정하는 수이다. 수에 정하지 않으면 EDITOR 수의 내용도 참고한다.
저장소 위치 관변수
Git재 작중인 저소를 참할 때 아래와 같은 환경수에 영는다.
*GIT_DIR * 수는 .git 렉토리의 위치를 정하는 수다. 수의 정하지 않으면 재 디렉토리에서부터
~ / 까지 한 위로 라가면서 .git 렉토리가 있는지 는다.
*GIT_CEILING_DIRECTORIES * 수는 .git 렉토리으려고 한 위로 라가는 작을 제어한다.
사용하는 시스의 저장장치를 고 쓰는 속도가 무지하게 느면 이 수를 적절하게 정한다. 불필요하게 .git
렉토리찾아서 계속 저장장치의 디렉토리돌아다니지 않도 된다.
*GIT_WORK_TREE * 수는 Git 소가 관리하는 실제 소스코드와 같일이 위치한 디렉토리정한다. 물론
실제 일을 사용하Bare 소가 경우에만 해당한다. --git-dir 옵션이나 GIT_DIR 수가 지정되었으나
--work-tree 옵션 또는 GIT_WORK_TREE 수 또는 core.worktree 정이 지정되지 않으면 재 디렉토리
렉토리상위 디렉토리로 가정한다.
*GIT_INDEX_FILE * 수는 Index 일의 위치를 정한다. Bare 소가 경우에만 해당한다.
*GIT_OBJECT_DIRECTORY * 수는 .git/objects 렉토리 위치를 정한다. Bare 소가 경우에만
해당한다.
*GIT_ALTERNATE_OBJECT_DIRECTORIES * 수는 콜론으로 분된 디렉토리 리스트(,
/dir/one:/dir/two:…)GIT_OBJECT_DIRECTORY 에서 을 수 없는 개을 때 사용할 디렉토리
정한다. 크기가 무지하게 큰 파일을 여러 프로젝트에서 유하고 있다면 이 수를 적절히 사용한다. 되는 내용을
지우고 특정 위치에서 개유해서 사용하로 저장공비를 일 수 있다.
Pathspec 변수
“pathspec” Git을 쓸 때 일이나 디렉토리의 경로(* 일드드 문자를 사용하는 경우를 포함)를 전달할 때 어
방식을 사용하는가에 대한 내용이다. .gitignore 일에서도 사용하고 git 명령(, git add *.c)에서도 사용한다.
GIT_GLOB_PATHSPECS, GIT_NOGLOB_PATHSPECS 수로는 Pathspec을 사용할 때 일드드 문자로 어
동작을 하게 할 지 정한다. GIT_GLOB_PATHSPECS 수의 1정하면 일드드 문자는 보사용하
일드드 문자의 할을 한다(). GIT_NOGLOB_PATHSPECS 수의 1정하면 일드드 문자를
일 이름의 일드드 문자로만 인한다. *.c 라고 하면 일 이름이 “\*.c” 일만 해당하고 확장자가 *.c
일은 해당하지 않는다. 환경 수에 독립적으로 각 명령에서 이를 선택하여 사용할 때는 :(glob) 또는 :(literal)
를 명시해서 사용할 수 있다. 예를 들어 :(glob)\*.c 이다.
*GIT_LITERAL_PATHSPECS * 수를 정하면 위 정 둘 다 적용하지 않는다. 일드드 문자는 무런 쓸모도
455
없게 되고, 수에 독립적으로 사용하는 접어도 마가지로 쓸 수 없게 된다.
*GIT_ICASE_PATHSPECS * 수를 정하면 대문자소문자를 가지 않게 된다.
커밋관변수
Git이 커을 만드는 작에서 대부분 git-commit-tree 명령을 실하고 나면 커가 만들어. 이 명령이
을 만들 때 커워넣을 정보를 가오거나 참고하는 환경수는 아래와 같. 환경수를 정하지 않는 경우는
환경일의 내용을 가져와 적용한다.
*GIT_AUTHOR_NAME * 수는 “author” 정보로 사용할 이름.
*GIT_AUTHOR_EMAIL * 수는 “author” 정보로 사용할 이일 주소.
*GIT_AUTHOR_DATE * 수는 “author” 정보로 사용할 타.
*GIT_COMMITTER_NAME * 수는 “committer” 정보로 사용할 이름.
*GIT_COMMITTER_EMAIL * 수는 “committer” 정보로 사용할 이일 주소.
*GIT_COMMITTER_DATE * 수는 “committer” 정보로 사용할 타.
*EMAIL * 수는 어환경일에도 user.email 정을 을 수 없는 경우 참하는 수다. 수마저
정하지 않으면 Git은 시스재 사용자정보시스호스트 정보를 합하여 사용한다.
네트워크 관변수
GitHTTP 프로토콜로 데이터를 전송할 때 curl 라이를 사용한다. GIT_CURL_VERBOSE 수를 정하면
curl 라이가 출력하는 상세한 정보를 볼 수 있다. curl -v 명령을 사용한 경우하다.
GIT_SSL_NO_VERIFY 수를 정하면 SSL 서를 인하지 않는다. HTTPS 프로토콜로 저소를 사용하는데
Self-signed 서를 사용할 때 이 수를 사용한다. 아직 서를 정상적으로 발않았지만, 스트를 위해
스트용 인서를 사용하는 경우를 예로 들 수도 있다.
GIT_HTTP_LOW_SPEED_TIME 수에 정한 시간 동GIT_HTTP_LOW_SPEED_LIMIT 수에 정한 당 전송
바이트 수에 치지 못하는 HTTP 전송속도가 나오면 Git은 데이터 전송을 중지한다. 정은 일의
http.lowSpeedLimit, http.lowSpeedTime 목보다 우한다.
GIT_HTTP_USER_AGENT 수는 GitHTTP 데이터 전송을 할 때 더에 사용자 에이전트 으로 사용할 문자열을
정한다. 적으로 사용하는 git/2.0.0 은 모이다.
Diff/Merge 변수
*GIT_DIFF_OPTS * 수는 이름이 못 지어진 변수다. git diff 명령을 실했을 때 경된 부분 아래위로
보여주는 라인의 개수를 절한다. 명령의 옵션으로 사용할 때는 -u<n> 이나 `--unified=<n>`로 사용한다.
*GIT_EXTERNAL_DIFF * 수는 diff.external 정보다 우한다. git diff 명령을 실하면 이 수에
정한 명령을 실한다.
456
*GIT_DIFF_PATH_COUNTER * 수나 *GIT_DIFF_PATH_TOTAL * 수의 정은 GIT_EXTERNAL_DIFF 또는
diff.external 정된 프로그에서 유용하게 사용한다. GIT_DIFF_PATH_TOTAL 수는 diff 명령이
할 때 보여주는 모든 일의 개수를 나타. GIT_DIFF_PATH_COUNTER 수는 그 일 중 지금 몇 번째 파일을
보여주고 있는지를 1로 시작하는 Index고 있다.
*GIT_MERGE_VERBOSITY * 수는 Recursive Merge 에 따른 시지 출력을 제어한다. 수가 사용할 수 있는
아래와 같5개의 수이다.
0 이 발생한 경우에만 마지에러 시지를 출력
1 이 발생한 경우에만 내용을 출력함
2 내용과 경된 내용을 출력함
3 경된 내용이 없는 일이라도 출력함
4 Merge 할 때 열어모든 일을 출력함
5 또는 그 이상의 정하면 디버그 시지까지 출력함
이 중 기2이다.
디버그 관변수
Git이 어디까지 실했는지 알고 은가? Git은 거의 모든 내부 동작에 대한 Trace 로그를 남길 수 있으며 환경수를
절해서 Trace 로그를 인할 수 있다. 수에 정할 수 있는 아래와 같.
“true”, “1”, “2” – stderr 표준에러출력으로 Trace 로그를 출력함(1 이상 10 이하의 자는 해당 FD로 출력함).
/ 로 시작하는 절대 경로 – Trace 로그를 해당 경로의 일에 기록함.
*GIT_TRACE * 수에 위와 같정하면 특정 로 지정하지 않은 모든 Trace 시지를 대상에 기록하거나
출력한다. Alias를 적용하거나 명령에 따라 Subprogram을 실다거나 하는 Trace인할 수 있다.
$ GIT_TRACE=true git lga
20:12:49.877982 git.c:554 trace: exec: 'git-lga'
20:12:49.878369 run-command.c:341 trace: run_command: 'git-lga'
20:12:49.879529 git.c:282 trace: alias expansion: lga =>
'log' '--graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all'
20:12:49.879885 git.c:349 trace: built-in: git 'log' '--
graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all'
20:12:49.899217 run-command.c:341 trace: run_command: 'less'
20:12:49.899675 run-command.c:192 trace: exec: 'less'
*GIT_TRACE_PACK_ACCESS * 수에 따라 Packfile 사용 내용을 출력한다. 출력 내용을 보면 번째 열은 접하는
Packfile의 이름을, 두 번째 열은 Packfile 에서 오프정보를 보여.
457
$ GIT_TRACE_PACK_ACCESS=true git status
20:10:12.081397 sha1_file.c:2088 .git/objects/pack/pack-
c3fa...291e.pack 12
20:10:12.081886 sha1_file.c:2088 .git/objects/pack/pack-
c3fa...291e.pack 34662
20:10:12.082115 sha1_file.c:2088 .git/objects/pack/pack-
c3fa...291e.pack 35175
# […]
20:10:12.087398 sha1_file.c:2088 .git/objects/pack/pack-
e80e...e3d2.pack 56914983
20:10:12.087419 sha1_file.c:2088 .git/objects/pack/pack-
e80e...e3d2.pack 14303666
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
*GIT_TRACE_PACKET * 수는 크 데이터 전송을 하는 경우 Trace 정보를 보여.
$ GIT_TRACE_PACKET=true git ls-remote origin
20:15:14.867043 pkt-line.c:46 packet: git< #
service=git-upload-pack
20:15:14.867071 pkt-line.c:46 packet: git< 0000
20:15:14.867079 pkt-line.c:46 packet: git<
97b8860c071898d9e162678ea1035a8ced2f8b1f HEAD\0multi_ack thin-pack side-
band side-band-64k ofs-delta shallow no-progress include-tag
multi_ack_detailed no-done symref=HEAD:refs/heads/master agent=git/2.0.4
20:15:14.867088 pkt-line.c:46 packet: git<
0f20ae29889d61f2e93ae00fd34f1cdb53285702 refs/heads/ab/add-interactive-
show-diff-func-name
20:15:14.867094 pkt-line.c:46 packet: git<
36dc827bc9d17f80ed4f326de21247a5d1341fbc refs/heads/ah/doc-gitk-config
# […]
*GIT_TRACE_PERFORMANCE * 수를 정하면 Git의 성관련Trace를 출력한다. 출력한 내용을 살펴보면 어
마나 시간이 걸려 실되었는지 인할 수 있다.
458
$ GIT_TRACE_PERFORMANCE=true git gc
20:18:19.499676 trace.c:414 performance: 0.374835000 s: git
command: 'git' 'pack-refs' '--all' '--prune'
20:18:19.845585 trace.c:414 performance: 0.343020000 s: git
command: 'git' 'reflog' 'expire' '--all'
Counting objects: 170994, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (43413/43413), done.
Writing objects: 100% (170994/170994), done.
Total 170994 (delta 126176), reused 170524 (delta 125706)
20:18:23.567927 trace.c:414 performance: 3.715349000 s: git
command: 'git' 'pack-objects' '--keep-true-parents' '--honor-pack-keep'
'--non-empty' '--all' '--reflog' '--unpack-unreachable=2.weeks.ago' '--
local' '--delta-base-offset' '.git/objects/pack/.tmp-49190-pack'
20:18:23.584728 trace.c:414 performance: 0.000910000 s: git
command: 'git' 'prune-packed'
20:18:23.605218 trace.c:414 performance: 0.017972000 s: git
command: 'git' 'update-server-info'
20:18:23.606342 trace.c:414 performance: 3.756312000 s: git
command: 'git' 'repack' '-d' '-l' '-A' '--unpack-unreachable=2.weeks.ago'
Checking connectivity: 170994, done.
20:18:25.225424 trace.c:414 performance: 1.616423000 s: git
command: 'git' 'prune' '--expire' '2.weeks.ago'
20:18:25.232403 trace.c:414 performance: 0.001051000 s: git
command: 'git' 'rerere' 'gc'
20:18:25.233159 trace.c:414 performance: 6.112217000 s: git
command: 'git' 'gc'
*GIT_TRACE_SETUP * 수를 정하면 Git재 어환경 위에서 동작하고 있는지 한 정보를
보여.
$ GIT_TRACE_SETUP=true git status
20:19:47.086765 trace.c:315 setup: git_dir: .git
20:19:47.087184 trace.c:316 setup: worktree:
/Users/ben/src/git
20:19:47.087191 trace.c:317 setup: cwd: /Users/ben/src/git
20:19:47.087194 trace.c:318 setup: prefix: (null)
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
동사니 변수
*GIT_SSH * 수를 정하면 GitSSH 모트로 연결할 때 ssh 명령 대신 정된 명령을 사용한다. $GIT_SSH
[username@]host [-p <port>] <command> 명령을 실한 것과 . GIT_SSH 수를 정하는 방식ssh
명령을 사용자 입고치는 가좋은 방법니다. ssh 명령의 다옵션을 사용할 수 없는 방식이기
459
때문이다. 따로 원하는 옵션들을 적용한 스크트를 하나 만들고 이 스크트를 수에 정하면 원하는 ssh 옵션
사용할 수 있다. ~/.ssh/config 환경일을 편하여 사용하는 것이 더 나을 수도 있다.
*GIT_ASKPASS * 수는 core.askpass 정보다 우한다. 수에 정하는 스크트나 프로그Git
사용자에게 호를 입력는 상에서 실되어 stdout 표준출력으로 출력하는 시지를 호로 받아서 처한다.
(Credential 에서 더 자세한 내용을 인할 수 있다.)
*GIT_NAMESPACE * 수를 정하면 Ref에 접할 때 네임이스로 사용한다. --namespace 옵션.
수는 서버 에서 유용하게 사용할 수 있다. 하나의 저에 여러 Fork를 운영하는 경우 이 수를 사용하여 Ref
하여 사용할 수 있다.
*GIT_FLUSH * 수를 정하면 Git시지를 면에 출력할 때 버를 사용하지 않고 시 출력한다. 1
정하면 소보다 훨씬 하게 시지 출력하고 0으로 정하면 상 버를 사용한다. 수에 정하지
않으면 기적으로 Git은 상절하여 출력한다.
*GIT_REFLOG_ACTION * 수는 reflog 명에 사용된다. 수에 작내용에 대한 명을 담아두Git
명령을 실하면 된다. 예를 들어 아래와 같.
$ GIT_REFLOG_ACTION="my action" git commit --allow-empty -m 'my message'
[master 9e3d55a] my message
$ git reflog -1
9e3d55a HEAD@{0}: my action: my message
요약
Git이 내부적으로 어떻게 동작하는지 뿐만 니라 어떻게 구현됐는지까지 알게 됐을 것이다. 에서는 저수
명령어인 Plumbing 명령어를 명했다. 다른 에서 우가 배Porcelain 명령어보다는 순하다. Git
내부적으로 어떻게 동작하는지 알면 Git게 하는가를 더 쉽게 이해할 수 있을 뿐만 니라 개인적으로 요한
나 스크트를 만들어 자신의 크플로를 개할 수 있다.
GitContent-addressable 일 시스이기 때문에 VCS 이상의 일을 할 수 있는 력한 도. 자는 자가
Git 내부 지을 활용해서 요한 접 만들면 좋. Git꼼꼼하고 디일하게
수 있게 되.
460
부록 A: 한 환경에서 Git 사용하기
이 책을 다 으면 Git 명령어를 사용하는 방법을 많이 배우게 된다. 그러면 로컬 파일을 관리하거나 너머에 있는
소에 연결하는 것 이상의 일들도 할 수 있다. GitCLI고 다른 도로도 사용할 수 있다. CLIGit 계의
한 부분일 뿐이고 터진리인 것도 니다. 에서는 다른 환경에서 Git을 어떻게 사용할 수 있는지 살펴보고 어
Git 이 있는지도 소개한다.
GUI
Git본진은 터이다. 새로운 기저 터에 추가될뿐더러 애초Git의 모든 기CLI로만 사용할 수 있다.
하지만 스트 세상이 늘 좋은 것도 니고 시각적 표현요할 때도 있다. 키고 하는 것을 편하게 느
사용자도 있다.
인터이스를 사용하느는 중요하지 않지만, 인터이스에 따라 크플로도 달라져야 한다. Git의 기해서
하는 라이트 프로그이 있는데 이런 도에서는 지원하는 방법으로만 Git을 사용해한다. 이런 으로 각
를 서로 비하고 수 없다. 마다 고유의 목적이 있다. 하지만 CLI로는 든 다 할 수 있다. GUI
라이트로 할 수 있는 일 중 CLI로 못 하는 일은 없다.
gitk git-gui
Git치하면 gitk git-gui 치된다.
gitk 는 히스토리를 그프로 보여. git log git grep 을 합놓은 GUI 라고 생각하면 된다. 프로젝트
히스토리를 시각해서 무일이 있었는지 살펴볼 때 이 도를 사용한다.
Gitk를 실하는 방법은 쉽다. cd 명령으로 Git 소 디렉토리로 이동해서 실한다.
$ gitk [git log options]
Gitk를 실할 때 옵션을 주고 실할 수 있는데 대부분 git log 의 것과 . 유용한 옵션으로 --all 이 있는데
HEAD의 히스토리니라 저소의 모든 커을 보여달라고 하는 옵션이다. Gitk아래와 같이 생.
461
그림 152. gitk 히스토리 .
위에 있는 히스토리git log --graph 의 출력과 비하게 생. 은 커은 부자계를 나타내고 색칠
스가 Ref. 란색 점HEAD아직 하지 경 내이다. 을 하나 선택하면 왼쪽에 코
치를 보여주고 오른에 요정보를 보여. 고 중간에는 히스토리하는 입력 폼이 있다.
git-gui 꼼꼼하게 커하는데 사용하는 커. 쉽게 실할 수 있다.
$ git gui
이 프로그아래처럼 실된다.
462
그림 153. 커밋 도구인 git-gui.
왼쪽에는 Index가 있다. 그 위에는 Unstaged 일들이 있고 아래에는 Staged 일이 있다.
하면 모든 일을 대 상수 있다. 일 이름을 선택하면 해당 일 내용을 보여.
오른에는 선택일의 경 내용이 Diff로 보여. Diff에서 오른하면 해당 라인이나 해당
Hunk를 하나Stage 할 수 있다.
오른에는 커밋 메시지들이 있다. 스트 스에 시지를 입력하고 “Commit” 하면 git
commit 을 실한 것과 . “Amend” 라디오 버선택하면 최근 도 수정할 수 있다. “Staged Changes”
에는 마지내용이 시된다. 것을 Stage 하거나 못 커한 것을 Unstage 하고 커밋 메시지를
수정하고 나서 다시 “Commit” 하면 새 커으로 경된다.
gitk git-gui 는 특정 일에 . gitk 는 히스토리 조회용이고 git-gui 는 커용 도. 이 도
다른 일은 할 수 없다.
GitHub 라이
GitHub'GitHub for Mac’'GitHub for Windows’라는 Git 라이트를 만들었다. 라이트는 Git의 모든
을 지원하지 않는다. 사람들이 많이 사용하는 크플로를 따도록 만들었다. 어떻게 생는지 한보자.
463
그림 154. GitHub for Mac.
그림 155. GitHub for Windows.
프로그은 거의 똑같이 생. 서 이 둘을 한 프로그이라고 생각하고 명한다. 는 이 도에 자세하게
명하지 않는다. 자세한 것은 명서를 참고하. 마도 “changes를 중심으로 사용하게 될 것이라서
“changes소개하려고 한다.
464
왼쪽에 있는 것은 이 라이트가 추적하고 있는 저소의 목록이다. 아래에 있는 “+” 하면 이
에 있는 저소를 추가하거나 새로 Clone 할 수 있다.
에는 커을 위한 이 있다. 시지를 입력하고 일을 라서 커할 수 있다. Windows 버전에서는 바로
아래 히스토리가 보여지지만 Mac 버전에서는 에 보여.
오른렉토리 변경된 부분을 보여주는 Diff . 을 하나 선택하면 해당 커의 내용만 보여.
오른위에 있는 “Sync” 누르면 외부 저동기한다.
GitHub 계정이 없어도 이 을 사용할 수 있다. GitHub 서비스GitHub이 제하는 크플로에
이지만 다른 호스트나 저소에도 사용할 수 있다.
설치
'GitHub for Windows'GitHub for Mac’은 각각 https://windows.github.comfrom
https://mac.github.com에서 내려을 수 있다. 프로그이 처음 실되면 이름과 이일 주소정을 하도록
내하고 'Credential Cache’CRLF 정도 사람들이 많이 사용하는 으로 똘똘하게 처한다.
데이트는 백그라운드로 다운로드하고 치해서 늘 신버전으로 유지한다. 들로 포함된 Git데이트하기 때문에
데이트는 고민할 요가 없다. 'GitHub for WindowsPosh-git이 적용된 Powershell을 실하는 단축아
만들어 . 이 부분은 좀 있다 명하.
소를 추가해보자. 라이트는 GitHub에서 접한 저소들의 목록을 보여주고 한Clone 할 수 있도록
내한다. 소가 있으면 간'Mac Finder’'Windows Explorer’에서 어다(Drag) 놓으면 왼쪽
소 목록에 추가된다.
장 워크플로
치하고 정을 마으면 Git을 사용하GitHub 라이트를 사용할 수 있다. GitHub 플로우에서
명한 “GitHub Flow” 를 지원하도록 계했다. 하지만 하는 일을 순하게 나보면 브랜치에 커하거나 모트
동기시키는 일로 나볼 수 있다.
브랜관리버전이 금 다. 'GitHub for Mac’에서는 Windows의 위에 있는 버으로 브랜치를 만들 수
있다.
그림 156. Mac“Create Branch” 버튼
'GitHub for Windows에서는 브랜치를 바는 위에서 브랜치 이름을 새로 입력하면 된다.
465
그림 157. Windows에서 브랜치 만들기.
브랜치를 만들면 시 커할 수 있다. 렉토리에서 작을 하고 GitHub 라이트로 을 바면 무엇을
수정했는지 보여. 밋 메시지를 입력하고 일을 선택하고 나서 “Commit” 하면('ctrl-enter’이나 '-
enter') 된다.
GitHub 라이트에서는 “Sync” 이 외부 저와 통신하는 방법이다. GitPush, Fetch, Merge, Rebase 각각
다른 기이지만 GitHub 라이트는 “Sync” 에 전부 었다.
1. git pull --rebase. 이 생기는 경우에는 git pull --no-rebase 이 실된다.
2. git push.
소를 동기할 때는 이 순서대로 명령어를 실하는 것이 일적이다. GitHub 라이트에서는 한 명령으로 전부
해서 시간을 절할 수 있다.
요약
이 원하는 특정 크플로에 적합하도록 계했다. 개발자든 비개발자든 금만 배우면 바로 프로젝트에 참여할
수 있다. 크플로하게 일하고 있다면 이 을 사용하는 것이 가장 최선이다.
다른 GUI
Git GUI 라이트에는 가 많다. 용으로 만들어것도 있고 것도 있다. Git 공식 웹사이트인 http://git-
scm.com/downloads/guis에는 많이 사용하는 라이트를 소개한다. Git 위키 사이트에는
(https://git.wiki.kernel.org/index.php/Interfaces,_frontends,_and_tools#Graphical_Interfaces) 더 많은
라이트가 정리돼 있다.
Visual Studio
Visual Studio 2013 Update 1부터 Git 라이트가 Visual Studio에 들어. Visual Studio에도 오랫동
버전관리 이 들어 있었다. 이 버전관리 시스Git과는 방식이 다. 앙 집이고 일을 그는 방식이다.
Visual Studio 2013Git에 어크플로를 따를 수 있도록 Git을 지원한다.
Git으로 관리하는 프로젝트나 git init 을 해서 새로 관리하도록 정한 프로젝트를 열면 이 기을 사용할 수 있다.
View > Team Explorer 선택한다. 그럼 "Connect" 를 보여주는데 아래와 같이 생.
466
그림 158. Team Explorer에서 Git 저장소에 결하기.
Visual Studio는 한 열었던 Git 프로젝트는 모기 때문에 하에 있는 목록에서 을 수 있다.
프로젝트가 목록에 없으면 "Add" 크를 해서 렉토리의 경로를 입력한다. Git 소 중 하나를 더
하면 Home 로 이동한다. Home Visual StudioGit "Home" . 처럼 생. Home 는 일
Git 터다. 코드를 작성할 때는 "Changes" 에서 많은 시간을 쓸 것이고 다른 동가 커한 코드를 내려을 때는
"Unsynced Commits"이나 "Branches" 를 사용하게 된다.
그림 159. Visual StudioGit "Home" .
Visual Studio에는 Git동되는 Task-focused UI도 있다. 여기에는 히스토리 , Diff , 모트 명령어 등등의
이 포함된다.
Eclipse
Eclipse에는 만든 Egit이라는 플러그인이 들어 있다. PerspectiveGit으로 경하면 바로 사용할 수 있다.
(에서 Window > Open > Other… > Git 순으로 선택한다)
467
그림 160. EclipseEGit.
Egit은 문서잘 돼 있다. Help > Help Contents 해 도움말 페이지를 열고 EGit Documentation
선택하면 EGit 문서를 볼 수 있다.
Bash
Bash 사용자라면 소 사용하던 대로 Git정해 사용할 수 있다. Git에는 에 유용한 플러그인이 들어있는데
자동으로 적용되않는다.
Git 소스에 들어 있는 contrib/completion/git-completion.bash 을 가다가 렉토리 어디
는다. .bashrc 일에 추가한다.
. ~/git-completion.bash
게 적용하고 Git 소에 들어가서 아래와 같이 입력한다.
$ git chec<tab>
468
git checkout 이라고 자동성 된다. Git 하위 명령어와 파, 모트, Refs까지 관련된 모든 것이 전부
자동성된다.
게다가 프프트에 Git 소의 정보를 보여수 있다. 순하게 보여주는 것도 가하고 꼼꼼하게 보여주는 것도
하다. 여기서는 사람들이 공통적으로 사용하는 현 브랜치 이름과 렉토리 정보를 보여주는 것을 살펴.
Git 소스 저소에서 contrib/completion/git-prompt.sh 일을 사해서 렉토리아래와 같
.bashrc 일에 추가한다.
. ~/git-prompt.sh
export GIT_PS1_SHOWDIRTYSTATE=1
export PS1='\w$(__git_ps1 " (%s)")\$ '
\w 현 워렉토리, \$ $ 를 출력하고, __git_ps1 " (%s)" git-prompt.sh 에 있는 함수에 포
아규먼트로 주고 호출하는 것이다. 이제부터는 Git 프로젝트 디렉토리에 들어가면 아래와 같이 보인다.
그림 161. bash 프트.
여기서 소개한 스크git-completion.bash git-prompt.sh 에 대해 자세히 알고 으면 코드를
보는 게 좋다.
Zsh
Zsh에는 Git자동성 스크트가 들어 있다. .zshrc 일에서 순히 autoload -Uz compinit &&
compinit 명령을 실하면 된다. ZshBash보다 더 력하다.
$ git che<tab>
check-attr -- display gitattributes information
check-ref-format -- ensure that a reference name is well formed
checkout -- checkout branch or paths to working tree
checkout-index -- copy files from index to working directory
cherry -- find commits not merged upstream
cherry-pick -- apply changes introduced by some existing commits
469
Zsh선택지가 여러 개일 때 순히 이름만 보여주지 않는다. 명도 함보여주고 키로 고를 수 있다. Git
명령어만이 니라 아규먼트도 자동성해. 게다가 저소의 모트나 Refs 이름과 일 이름 은 것도
자동성한다. Zsh는 모든 것을 제시한다.
Zsh에는 vcs_info 라는 프레임워크가 포함있다. 여기에는 재 사용하는 VCS정보가 들어있다. ~/.zshrc 일에
아래 라인을 추가하면 오른프트에 브랜치 이름이 시된다.
autoload -Uz vcs_info
precmd_vcs_info() { vcs_info }
precmd_functions+=( precmd_vcs_info )
setopt prompt_subst
RPROMPT=\$vcs_info_msg_0_
# PROMPT=\$vcs_info_msg_0_'%# '
zstyle ':vcs_info:git:*' formats '%b'
에서 Git 소 디렉토리로 이동하면 터오른현 브랜치 이름을 아래와 같이 보여. (물론 한 것만
돌리왼쪽 프트에서도 된다.)
그림 162. zsh 프트 .
vcs_info에 대한 자세한 정보는 zshcontrib(1) 뉴얼 이지를 보거나 http://zsh.sourceforge.net/Doc/
Release/User-Contributions.html#Version-Control-Information에서 인한다.
vcs_infoGit에 들어 있는 git-prompt.sh 접 수정해서 사용해도 된다. 자세한 내용은 https://github.com/
git/git/blob/master/contrib/completion/git-prompt.sh에서 인한다. git-prompt.sh BashZsh
470
호환된다.
Zsh령함을 이어 내는 프레임워크가 있다. "oh-my-zsh"이 대적인데 https://github.com/robbyrussell/oh-
my-zsh에서 을 수 있다. Git 자동성도 "oh-my-zsh" 플러그인을 사용하면 되고 브랜치 이상의 정보를 보여주는
한 프프트 마도 제한다. oh-my-zsh .은 프프트 마를 적용한 모습이다.
그림 163. oh-my-zsh .
Git in Powershell
Windows표준 CLI cmd.exe Git을 사용하기에 로 좋지 않다. Powershell을 쓸 줄 안다면
Powershell을 사용하는 것이 . PowerShellWindowsDebian 은 환경에서 사용한다면 이어지는
내용을 동일하게 적용해볼 수 있다. Posh-Git(https://github.com/dahlbyk/posh-git) 이라는 프로젝트가 있어서 Tab
자동성과 저소 상를 보여주는 프프트도 사용할 수 있다.
그림 164. Posh-git을 사용 중인 Powershell.
설치
요한 것 (Windows 해당)
PowerShell 스크트가 실되게 하려면 우ExecutionPolicy 정책을 RemoteSigned (Undefined 또는
471
Restricted 제외한 )으로 경해한다. RemoteSigned AllSigned 으로 정하면 스크트를
하기 위해 전자서명 과정이 요하다. RemoteSigned 으로 정하면 ZoneIdentifierInternet으로 정된
경우(주로 웹에서 다운로드한 )만 전자서명이 요하고 나일에 대해서는 전자서명이 요하지 않다.
Windows 시스관리한이 있다면 모든 사용자가 PowerShell을 사용할 수 있도록 "-Scope LocalMachine"
옵션을 사용할 수 있다. 적인 사용자라면 관리한이 없기 때문에 "-Scope CurrentUser" 옵션으로 자신만이
사용가하도록 정할 수 있다. PowerShellScope에 대한 자세한 내용은 https://technet.microsoft.com/de-
de/library/hh847849.aspx 에서 찾아볼 수 있다. PowerShellExecutionPolicy에 대한 자세한 내용은
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy
에서 찾아볼 수 있다.
> Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy RemoteSigned
-Force
PowerShell 갤러리로 설치
PowerShell 버전 5 이상을 사용하거나 PowerShell 4PackageManagement (Cmdlets)치해서
사용한다면 키지 관리자를 해서 Posh-Git치할 수 있다.
자세한 요https://docs.microsoft.com/en-us/powershell/scripting/gallery/overview 에서 인할 수
있다.
> Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
> Update-Module PowerShellGet -Force
> Install-Module Posh-Git -Scope AllUsers
Posh-Git치할 모든 사용자에 치하지 않도 자신만 사용하게 "-Scope CurrentUser" 옵션을 적용한다. 코드의
번째 명령을 실했을 때 Module 'PowerShellGet' was not installed by using Install-Module
은 오류 메시지가 발생한다면 다음 명령을 저 실해보기 바.
> Install-Module PowerShellGet -Force -SkipPublisherCheck
이 명령을 실한 후에 서 실한 명령을 다시 실. 이 오Windows Powershell에 이포함되어 배포한
의 인서가 일치하지 않기 때문이다.
PowerShell 프트에 Git 정보
PowerShell 프트에 Git 정보를 시하려면 posh-gitImport 한다. 이를 자동으로 하려면 import 문을
$profile 스크트에 추가하면 된다. 이 스크트는 PowerShell 프트가 나타때 마다 실된다. 해 둘 부분은
$profile 스크트가 여일 수 있다는 이다. console을 위한 스크ISE(합 스크팅 환경)를 위한 스크트가
되어 있을 수 있다.
472
> New-Item -Name $(Split-Path -Path $profile) -ItemType Directory -Force
> 'Import-Module Posh-Git' | Out-File -Append -Encoding default -FilePath
$profile
소스로 설치
https://github.com/dahlbyk/posh-git 에서 Posh-Git을 내려받아 WindowsPowershell 렉토리
놓는다. 관리한으로 Powershell 프트를 열고 아래와 같이 실한다.
> cd ~\Documents\WindowsPowerShell\Module\posh-git
> .\install.ps1
profile.ps1 일에 추가한 posh-git 은 프프트를 새로 열 때 부터 적용된다.
요약
에서는 각 환경에서 Git하는 방법과 다한 개발도Git 소에 연결하는 방법을 배.
473
부록 B: 플리이션에 Git 넣기
개발자가 사용하는 은 버전 관리 구와 통합될 요가 있다. 개발자가 니더라도 문서 편
프로그에서 버전 관리가 되면 우 좋다. Git우 다한 시나오를 지원한다.
Git을 지원하는 을 만들려면 질적으로 가지 방법 중 하나를 선택하게 된다. git 명령어를
시키는 방법이 있고 Git 라이에 포함시사용하는 방법이 있다. 이어지는 내용을
한 명령어 실을 사용하는 방법인하고 에 포함시사용하는 주요 Git 라이인한다.
Git 명령어
프로세스를 우고(Spawn) Git 명령어를 실하는 방법이 있다. 이게 가장 표준적인 방법으로 Git의 모든 기
사용할 수 있다. 만한 환경에서는 명령어를 프로세스로 실하는 것은 간로 이 방법은 사용하기 운 편이다.
그러나 이 방법가지 제이 있다.
과가 스트로 출력된다. Git이 상에 따라 다게 출력하는 과를 한다. 진행태와 결과 정보를
분해서 잘 읽해서 어렵고 에러 나기 쉽다.
는 에러 처가 어렵다. 소가 있거나 사용자가 정했을 때 Git은 그제대로 실되지 않을 뿐이다.
마지막 결점은 프로세스를 관리한다는 이다. 도의 프로세스로 Git을 실하기 때문에 불필요한
복잡성이 추가된다. 여러 프로세스를 하는 일은 지뢰밭이라 할 수 있다. 특히 동시에 여러 프로세스가 한 저소에
하면 `!@#$%^&*`되기 쉽다.
Libgit2
다른 방법으로는 Libgit2 라이가 있다. Libgit2Git에 의존하지 않는다. 프로그에서 사용하기 좋게 API
계했다. http://libgit2.github.com에서 내려을 수 있다.
API가 어떻게 생는지 경해보자.
474
// Open a repository
git_repository *repo;
int error = git_repository_open(&repo, "/path/to/repository");
// Dereference HEAD to a commit
git_object *head_commit;
error = git_revparse_single(&head_commit, repo, "HEAD^{commit}");
git_commit *commit = (git_commit*)head_commit;
// Print some of the commit's properties
printf("%s", git_commit_message(commit));
const git_signature *author = git_commit_author(commit);
printf("%s <%s>\n", author->name, author->email);
const git_oid *tree_id = git_commit_tree_id(commit);
// Cleanup
git_commit_free(commit);
git_repository_free(repo);
라인은 Git 소를 여는 코드다. git_repository 타입은 에 있는 저소 정보에 대한 들을 나타.
git_repository_open 소드는 렉토리.git 더 경로를 알 때 사용한다. 소 경로를 정히 모를
때는 git_repository_open_ext 소드로 는다. git_clone 소드와 관련소드는 원에 있는 저소를
Clone 할 때 사용한다. git_repository_init 은 저소를 새로 만들 때 사용한다.
rev-parse 을 사용하는 두 번째 코드는 HEAD가 가키는 커을 가온다. (자세한 내용은 브랜치로 가키기 참고)
git_object 포인터는 Git 데이터이스에 있는 개를 가. git_object 가지 타입의 부모
타입이다. 타입들은 git_object 에 해당하는 부분에 대해서는 리 구조. 는 자이라면
스팅해도 전하다. git_object_type(commit) 처럼 호출하면 GIT_OBJ_COMMIT 한다.
git_commit 포인터로 스팅해도 된다.
그다음 록은 커정보를 는 코드다. 마지라인의 git_oid Libgit2에서 SHA-1 을 나타내는 타입이다
이 예제를 보면 가지 코을 알 수 있다.
포인터를 정의하고 그 포인터Ref 스트을 주고 Libgit2 소드를 호출한다. 소드는 정수 타입의 에러 코드를
한다. 0 이 성이고 다른 은 에러다.
Libgit2가 포인터에 을 할당해주지만, 사용자가 해제해한다.
Libgit2하는 const 포인터는 해제하지 말아야 한다. 해당 가 속한 객체가 해제될 때 문제가 된다.
C로 코하는 것은 원좀 고.
마지라인을 이유로 Libgit2C에서 사용할 가성은 . 어나 환경에서 사용할 수 있는 Libgit2
바인이 있어서 Git 소를 쉽게 다수 있다. Rugged라는 Ruby 바인을 사용해서 위의 예제를 재작성해 보자.
Rugged에 대한 자세한 정보는 https://github.com/libgit2/rugged에 있다.
475
repo = Rugged::Repository.new('path/to/repository')
commit = repo.head.target
puts commit.message
puts "#{commit.author[:name]} <#{commit.author[:email]}>"
tree = commit.tree
해보면 코드가 더 간. Rugged는 예외를 사용해서 더 간하다. 하지만 ConfigError ObjectError
은 에러가 발생할 수 있다. Ruby는 가비지 콜렉을 사용하는 어라서 소스를 해제하지 않도 된다. 좀 더
복잡한 예제를 살펴보자. 새로 커하는 예제다.
blob_id = repo.write("Blob contents", :blob)
index = repo.index
index.read_tree(repo.head.target.tree)
index.add(:path => 'newfile.txt', :oid => blob_id)
sig = {
Ê :email => "bob@example.com",
Ê :name => "Bob User",
Ê :time => Time.now,
}
commit_id = Rugged::Commit.create(repo,
Ê :tree => index.write_tree(repo),
Ê :author => sig,
Ê :committer => sig,
Ê :message => "Add newfile.txt",
Ê :parents => repo.empty? ? [] : [ repo.head.target ].compact,
Ê :update_ref => 'HEAD',
)
commit = repo.lookup(commit_id)
일 내용이 담긴 Blob을 만든다.
IndexHead Tree우고 만든 Blobnewfile.txt 일로 추가한다.
ODB(Object Database)에 새 트를 만든다. 할 때는 새 트요하다.
AuthorCommitter정보는 한 사람(Signature)으로 한다.
밋 메시지를 입력한다.
할 때 부모가 요하다. 여기서는 HEAD를 부모로 사용한다.
Rugged (and Libgit2)는 커할 때 Ref 신 여부를 선택할 수 있다.
한 커SHA-1 해시로 Commit 객체 져와 사용한다.
Ruby 코드는 간하고 깔끔하다. Libgit2을 사용하는 것이기 때문에 여전히 빠르. 루비스트가 니라면 다른 바인
있는 다른 바인을 사용할 수 있다.
476
Libgit2으로 Git확장하는 일도 가하다. Libgit2에서는 커스“Backend” 를 만들어 사용할 수 있다. Git
하는 방법 말고 다른 방법으로도 저할 수 있다. 이것을 'Pluggability’라고 부른다. , Ref , 데이터
이스를 커스“Backend” 에 저할 수 있다.
이게 무인지 예제를 살펴보자. 아래 코드는 Libgit2 팀이 제하는 Backend 예제에서 가왔다. Libgit2 팀이
하는 전예제는 https://github.com/libgit2/libgit2-backends에 있다. 데이터이스의 Backend
어떻게 사용하는지 보자.
git_odb *odb;
int error = git_odb_new(&odb);
git_odb_backend *my_backend;
error = git_odb_backend_mine(&my_backend, /*…*/);
error = git_odb_add_backend(odb, my_backend, 1);
git_repository *repo;
error = git_repository_open(&repo, "some-path");
error = git_repository_set_odb(odb);
(에러는 처리하지 않. 실제로 사용할 때는 완벽하리라 믿는다.)
“Frontend” 로 사용할 ODB(Object DataBase)를 하나 한다. 실제로 저하는 “Backend” 이터로
사용한다.
ODB Backend한다.
FrontendBackend를 추가한다.
소를 열고 우가 만든 ODB를 사용하도록 정한다. 그러면 개를 우가 만든 ODB에서 는다.
그런데 git_odb_backend_mine ? 이 함수는 우ODB 생성자다. 여기서 원하는 대로 Backend를 만들어
주고 git_odb_backend 구조체우면 된다. 아래처럼 만든다.
477
typedef struct {
Ê git_odb_backend parent;
Ê // Some other stuff
Ê void *custom_context;
} my_backend_struct;
int git_odb_backend_mine(git_odb_backend **backend_out, /*…*/)
{
Ê my_backend_struct *backend;
Ê backend = calloc(1, sizeof (my_backend_struct));
Ê backend->custom_context = …;
Ê backend->parent.read = &my_backend__read;
Ê backend->parent.read_prefix = &my_backend__read_prefix;
Ê backend->parent.read_header = &my_backend__read_header;
Ê // …
Ê *backend_out = (git_odb_backend *) backend;
Ê return GIT_SUCCESS;
}
my_backend_struct 번째 버는 드시 git_odb_backend 돼야 한다. Libgit2가 동작하는
구조맞아야 한다. 버는 상없다. 구조체 크기는 커도 되고 작도 된다.
함수에서 구조체를 할당하고 커스버에 요한 정보를 정한다. Libgit2에서 요한
parent 구조체운다. include/git2/sys/odb_backend.h 소스를 보면 git_odb_backend 구조체
버가 어것이 있는지 알 수 있다. 목적에 따라 어떻게 사용해하는지 인해한다.
다른 바인
Libgit2 바인은 많은 어로 구현돼 있다. 을 쓰는 시에서 거의 완벽하게 구현됐다고 생각되는 것은 여기서
소개한다. 그 외에도 C++, Go, Node.js, Erlang, JVM 등 많은 어로 구현돼 있다. https://github.com/libgit2에 가서
살펴보면 어바인이 있는지 찾아볼 수 있다. 여기서는 HEAD가 가키는 커시지를 가오는 코드를 보여.
LibGit2Sharp
NET이나 Mono 애플리이션을 만드는 중이라면 LibGit2Sharp (https://github.com/libgit2/libgit2sharp)
사용하면 된다.
이 바인C#으로 작성했고 Libgit2음에도 이티이 나도록 꼼꼼하게 계했다. 밋 메시지를 가오는
예제를 보자.
478
new Repository(@"C:\path\to\repo").Head.Tip.Message;
Windows 데스크에서 쉽게 사용할 수 있도록 NuGet 키지도 존재한다.
objective-git
Apple 플랫폼용 을 만들고 있다면 어가 Objective-C일 것이다. 이 환경에서는 Objective-Git
(https://github.com/libgit2/objective-git)을 사용할 수 있다. Objective-C 예제를 보자.
GTRepository *repo =
Ê [[GTRepository alloc] initWithURL:[NSURL fileURLWithPath:
@"/path/to/repo"] error:NULL];
NSString *msg = [[[repo headReferenceWithError:NULL] resolvedTarget]
message];
Objective-gitSwift에서도 사용할 수 있기 때문에 Objective-C니라고 정하지 않도 된다.
pygit2
Python용 바인Pygit2라고 부른다. http://www.pygit2.org/에서 을 수 있다. 예제를 보자.
pygit2.Repository("/path/to/repo") # open repository
Ê .head # get the current branch
Ê .peel(pygit2.Commit) # walk down to the commit
Ê .message # read the message
을거리
Libgit2를 자세히 명하는 것은 이 책의 목적에서 어난다. Libgit2 에 대해서 부하고 다면 Libgit2 가이드
(https://libgit2.github.com/docs)API 문서(https://libgit2.github.com/libgit2)를 참고한다. Libgit2 바인
대해서 알고 다면 해당 프로젝트의 README 일과 스트를 참고해한다. 어보면 어디서부터 시작해하는지
알려.
JGit
Java에는 JGit이라는 훌륭Git 라이가 있다. JGit에는 Git 이 한가득 구현돼 있다. 순수하게 Java
작성됐고 Java 커뮤니티에서 사용한다. The JGit 프로젝트는 Eclipse 지를 었고 이지는
http://www.eclipse.org/jgit에 있다.
479
설치하기
JGit을 프로젝트에 추가해서 코을 시작하는 방법은 여러 가지다. 그중 Maven을 사용하는 방법이 가쉽다. pom.xml
일에 <dependencies> 그를 아래와 같이 추가한다.
<dependency>
Ê <groupId>org.eclipse.jgit</groupId>
Ê <artifactId>org.eclipse.jgit</artifactId>
Ê <version>3.5.0.201409260305-r</version>
</dependency>
version 은 시간에 따라 것이기 때문에 http://mvnrepository.com/artifact/org.eclipse.jgit/
org.eclipse.jgit에서 신 버전을 인해한다. 추가하면 Maven이 우가 명시한 버전의 JGit을 자동으로 추가해.
면 수동으로 바이너리관리하고 을 수도 있다. http://www.eclipse.org/jgit/download 에서 드된 바이너리
내려는다. 이 바이너리를 이용해서 아래와 같컴파일할 수 있다:
javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java
java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App
Plumbing
JGitAPI는 크게 PlumbingPorcelain으로 나수 있다. 이 둘은 Git 용어이고 JGit도 이에 따라 나.
사용자가 사용하는 Git 명령어를 Porcelain 명령어라고 부는데 이와 관련APIProcelain API라고 부른다. 대로
Plumbing API는 저소 개를 저수에서 접 사용하는 API.
JGit을 사용하는 것은 Repository 클래스의 인스스를 만드는 것으로 시작한다. 일 시스에 있는 저소에 접
때는 FileRepostiorybuilder 를 사용한다.
// Create a new repository
Repository newlyCreatedRepo = FileRepositoryBuilder.create(
Ê new File("/tmp/new_repo/.git"));
newlyCreatedRepo.create();
// Open an existing repository
Repository existingRepo = new FileRepositoryBuilder()
Ê .setGitDir(new File("my_repo/.git"))
Ê .build();
Git 소를 나타내는 정보를 하나더 넘. 넘기는 정보에 따라 금 다른 API를 사용한다. 환경 수를
(.readEnvironment()) 렉토리를 주고 Git 렉토리을 수도 있고(.setWorkTree(…).findGitDir
()) 예제로 보여것처럼 .git 렉토리를 바로 넘수도 있다.
Repository 인스스를 기으로 온일을 다 할 수 있다. 예제를 하나 보자.
480
// Get a reference
Ref master = repo.getRef("master");
// Get the object the reference points to
ObjectId masterTip = master.getObjectId();
// Rev-parse
ObjectId obj = repo.resolve("HEAD^{tree}");
// Load raw object contents
ObjectLoader loader = repo.open(masterTip);
loader.copyTo(System.out);
// Create a branch
RefUpdate createBranch1 = repo.updateRef("refs/heads/branch1");
createBranch1.setNewObjectId(masterTip);
createBranch1.update();
// Delete a branch
RefUpdate deleteBranch1 = repo.updateRef("refs/heads/branch1");
deleteBranch1.setForceUpdate(true);
deleteBranch1.delete();
// Config
Config cfg = repo.getConfig();
String name = cfg.getString("user", null, "name");
이 예제가 어인지 하나살펴보자.
라인에서 master Ref었다. Jgitrefs/heads/master 에 있는 master Ref를 가져와서 인스스를
한다. 객체Ref에 대한 정보를 을 수 있다. 이름(.getName()), Ref가 가키는 개(.getObjectId()),
Symbolic Ref가 가키는 Ref(.getTarget())를 이 객체을 수 있다. Ref 인스스는 Ref
나타내고 그가 “Peeled” 인지도 인할 수 있다. “Peeled” 질을 다 그러니까 커를 가키는
한다.
두 번째 라인은 master 가 가키는 ObjectId 인스스를 한다. ObjectId객체SHA-1 해시 정보다. 실제로
객체Git 객체 데이터이스에 존재하는지는 상없다. 라인도 ObjectId 인스스를 하는데 JGit에서 rev-
parse 을 어떻게 다하는지 보여. 이 문브랜치로 가키기에서 명했다. Git이 이해하는 표현은 전부
사용 가하다. 표현식으면 해당 객체하고 니면 null한다.
그다음 라인은 객체의 내용을 어서 보여. ObjectLoader.copyTo() 함수로 객체의 내용을 표준출력으로
출력(Stream)했다. ObjectLoader에는 객체의 타입과 크기를 알려주거나 객체의 내용을 바이트 배열에 담아하는
소드도 있다. 일이 지도 인할 수 있다. .isLarge() 라는 소드가 true 하면 큰 파일이다. 큰 파일이면
.openStream() 호출해서 ObjectStream 인스스를 는다. 이 인스스는 일InputStream으로 한
전부 올리지 않고 데이터를 처할 수 있게 해.
그다음 라인은 새 브랜치를 만드는 것을 보여. RefUpdate 인스스를 만들고, 터를 정하고 나서
481
.update() 를 호출하면 브랜치가 생성된다. 그다음 라인은 만든 브랜치를 제하는 코드다.
.setForceUpdate(true) 요하다. 이것을 빼으면 .delete() REJECTED 하고 무 일도
일어나지 않는다.
마지예제는 user.name 이라는 을 가오는 것이다. 이 코드는 마치 해당 저소의 local 정만 어서
Config 객체하는 것 지만, global 정과 system 정까지 잘 찾아서 적용해.
여기서는 Plumbing API보기 정도만 보여. 이용 가소드와 클래스가 많이 있다. JGit의 에러를
하는 방법도 생했다. JGIT API에서는 JGit에서 정의한 NoRemoteRepositoryException,
CorruptObjectException, NoMergeBaseException 은 예외뿐만 니라 IOExceptioin Java 표준
예외도 던.
Porcelain
Plumbing API로도 모든 일을 다 할 수 있지만, 적인 상에 사용하기에는 좀 . Index일을 추가하거나
새로 커하는 것 은 일은 Porcelain API. Porcelain API는 고수에서 사용하기 편하게 했고 Git 클래스의
인스스를 만드는 것으로 시작한다.
Repository repo;
// construct repo...
Git git = new Git(repo);
Git 클래스는 스타일의 소드의 합이라서 복잡해 보이는 일을 쉽게 할 수 있다. git ls-remote 명령어처럼
동작하는 예제를 살펴보자.
CredentialsProvider cp = new
UsernamePasswordCredentialsProvider("username", "p4ssw0rd");
Collection<Ref> remoteRefs = git.lsRemote()
Ê .setCredentialsProvider(cp)
Ê .setRemote("origin")
Ê .setTags(true)
Ê .setHeads(false)
Ê .call();
for (Ref ref : remoteRefs) {
Ê System.out.println(ref.getName() + " -> " + ref.getObjectId().name());
}
Git 클래스는 이런 으로 사용한다. 소드가 해당 Command 인스스를 하면 으로 소드를 호출해서
터를 정하고 .call() 을 호출하는 시에 실제로 실된다. 이 예제는 origin 모트의 'tag’를 요하는
예제다. 'head’는 빼고 요한다. 사용자 인CredentialsProvider 객체를 사용한다는 을 기하자.
Git 클래스로 실하는 명령은 우 많다. 에게 add, blame, commit, clean, push, rebase, revert,
reset 명령 고도 많다.
482
을거리
여기서는 JGit금만 보여. 자세히 알고 다면 아래 크에서 도움을 수 있다.
공식 JGit API 문서: https://www.eclipse.org/jgit/documentation 표준 Javadoc 문서로 쓰는 JVM
IDE에 추가할 수 있다.
JGit Cookbook: https://github.com/centic9/jgit-cookbook JGit으로 무엇을 할 수 있는지 보여주는 예제가
많다.
go-git
Go 어로 작성한 서비스에 Git 합하려고 한다면 순수하게 Go 어로만 작성된 라이리 구현체가 있다. Go
어로 작성된 라이기에 이티의존성이 없으며 리관리에서 오성이 적다. 또한 Go 어로
작성되었기에 Go 표준 정 도(CPU, 프로, 태 탐지 등)를 사용할 수 있다.
go-git확장성과 호환성에 중Plumbing API 대부분을 지원한다. 관련 내용은 https://github.com/src-d/
go-git/blob/master/COMPATIBILITY.md 에서 인할 수 있다.
Go 라이API를 사용하는 기적인 예제는 다음과 .
import "gopkg.in/src-d/go-git.v4"
r, err := git.PlainClone("/tmp/foo", false, &git.CloneOptions{
Ê URL: "https://github.com/src-d/go-git",
Ê Progress: os.Stdout,
})
위 코드를 실하면 Repository 인스스를 할당게 되고 이 인스스를 해 저소 정보를 가오거나 어떤 변화
수 있다.
// HEAD 키는 브랜 Ref 오기
ref, err := r.Head()
// Ref 키는 오기
commit, err := r.CommitObject(ref.Hash())
// 히스토리 정보를 오기
history, err := commit.History()
// 히스토리에서 하나 반복하여 정보를 출력하기
for _, c := range history {
Ê fmt.Println(c)
}
483
go-git가지 주목할만한 고이 있다. 하나는 플러그 가한 저소 시스이며 Libgit2“Backend”
하다. 본 구현소이기에 접속도가 를수 에 없다.
r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
Ê URL: "https://github.com/src-d/go-git",
})
플러그 가한 저소는 다한 재옵션을 제한다. 예를 들어 https://github.com/src-d/go-git/tree/master/
_examples/storage 내용을 보면 런스, , 정정보 등을 Aerospike 데이터이스에 저하는 예제를 볼 수
있다.
다른 고으로는 유일 시스추상가 있다. https://godoc.org/github.com/src-d/go-billy#
Filesystem 문서를 보면 쉽게 일을 여러가지 다른 방식으로 저하는 내용을 볼 수 있다. 하나의 큰 파
할 수도 있고 에 모적재시수도 있다.
또 다른 고을 사용하는 예제로 세세하게 정가HTTP 라이트를 사용하는 구현https://github.com/
src-d/go-git/blob/master/_examples/custom_http/main.go 에서 찾아볼 수 있다.
customClient := &http.Client{
Ê Transport: &http.Transport{ // 모든 서를 과시키기
Ê TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
Ê },
Ê Timeout: 15 * time.Second, // 15 임아웃
Ê CheckRedirect: func(req *http.Request, via []*http.Request) error
{
Ê return http.ErrUseLastResponse // 다이 응답 따라가지 않기
Ê },
}
// https 라이트를 새로 작성한 의의 라이트로 교체하기
client.InstallProtocol("https", githttp.NewClient(customClient))
// 새로 정한 라이트를 사용하여 https 주소로 시작하는 소를 Clone 하기
r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{URL: url})
더 읽거리
go-git의 다한 기을 모다루는 것은 이 책이 을 수 없는 영에 있다. go-git가 생기고 있다면
https://godoc.org/gopkg.in/src-d/go-git.v4 로 가서 API 문서를, https://github.com/src-d/go-git/tree/master/
_examples 로 가서 다구현 예제를 찾아보기 바.
484
부록 C: Git 명령어
이 책에서 Git 명령어를 많이 명하지만, Git명하기 위해서 중간마다 명하는 것뿐이다. 명을 해할 수 있기
때문에 명령어 중심으로 살펴보지 않는다. 에서는 여기저기 있는 명령어 사용을 한에 볼 수 있도록
한다.
책 전에서 언급했던 Git 명령어를 전부 살펴보는데 명령어를 용도에 따라 그으로 어 놓았다. 해당 명령어를 어디에
쓰는지 명하고 어디에서 찾아볼 수 있는지도 기한다.
설치와 설정
많이 사용하는 명령어가 개 있다. 바로 config help 명령이다. 이 명령은 일 사용한다.
git config
Git에는 정할 수 있는 이 수백 가지에 달한다. 사용자의 취향에 따라 다게 동작하도록 정할 수 있다. 이 명령으로
사용자이름이나 터, 기 등을 정한다. 소마다 다로벌하게 정할 수 있는데 각각
일이 다.
git config 명령은 이 책의 모든 에서 사용한다.
Git을 처음 사용할 때 이름, 일 주소, 기는 어떻게 정하는지는 Git 에서 명한다.
어떻게 단축 명령어를 만드는지는 Git Alias에 있다. 매번 긴 옵션줄줄 입력하지 않도 된다.
git pull 명령을 실할 때 --rebase 옵션으로 동작하게 하는 방법Rebase 하기에 있다.
HTTP 호를 저하는 방법Credential 를 보면 된다.
Git에 데이터를 때 사용하는 SmudgeClean 터를 정하는 방법드 치환에 있다.
마지으로 git config 명령 자에 대한 명은 Git 정하기에 있다.
git help
git help 명령은 Git에 포함된 문서를 보여. 에서는 많이 사용하는 것만 간명한다. `git help
<command>`라고 실하면 해당 명령어에 어옵션이 있고 어떻게 사용하는지 알려.
git help 명령은 도움보기에 소개한다. `git shell`을 서버에 정하는 방법서버 정하기에서 보여.
프로젝트 가져오기와 생성하기
Git 소는 가지 방법으로 만든다. 크 어가에 있는 저소를 사해오거나 기존 프로젝트 디렉토리에서
소를 새로 생성할 수 있다.
485
git init
프로젝트 디렉토리로 가서 `git init`이라고 실한다. 렉토리Git 소가 새로 만들어지고 프로젝트를 버전 관리
수 있다.
Git 소 만들기에서 로에 저소를 만드는 방법명한다.
“master” 에서 다른 브랜치로 경하는 방법모트 브랜에 소개한다.
서버에 Bare 를 보면 Bare 소를 만드는 방법이 나있다.
마지으로 git init 명령을 실하면 내부에서 어일이 일어나는 지 Plumbing 명령과 Porcelain 명령에서
명한다.
git clone
git clone 은 사실 다른 명령어를 개 실한다. 렉토리를 만들고 디렉토리로 들어가고 나서 git init 명령으로
Git 소를 만든다. 그다음 입력한 URLorigin 이라는() 이름의 모트로 추가하고(git remote add)
git fetch 명령으로 모트 저소에서 데이터를 가온다. 마지으로 렉토리Checkout 한다
(git checkout).
git clone 명령은 이 책 어디에서나 볼 수 있는 명령이지만 가장 설명이 몇 곳을 소개한다.
이 명령은 기존 저소를 Clone 하기에서 명했고 바로 따라 할 수 있는 예제도 보여.
--bare 옵션을 주고 렉토리 없는 Git 소를 사하는 방법서버에 Git 치하기에서 다.
Bundle 일로 된 Git 소를 다시 수도 있는데 Bundle에서 소개한다.
마지으로 --recursive 옵션으로 Clone 할 때 서까지 Clone 하는 방법포함한 프로젝트
Clone에서 명한다.
이 명령은 여기에 정한 부분 이외에서도 많은 에서 사용했지만, 차근차근 잘 설명한 으로 정했다.
스냅샷 다
Stage 하고 커하는 정도의 주 기적인 크플로는 명령어 개만 알면 된다.
git add
git add 명령은 렉토리에서 Staging Area(“index”)컨텐트를 추가하는 명령어다. git commit 명령은
오로지 Staging Area만 바라보기 때문에 git add 명령으로 커할 스냅샷한다.
이 명령은 우 중요한 명령어라서 이 책에서 수도 더 언급한다. 여기서 어떻게 사용하는지 잘 설명한 찾아보자.
`git add`일을 새로 추적하기에서 자세히 명한다.
이 명령는 시에도 요하다. 의 기에서 어떻게 사용하는지 명한다.
486
화형 명령에서 수정한 일 일부분을 대화형으로 Stage 하는 방법을 보여.
마지으로 이 명령이 내부적으로 어떻게 동작하는지 이해할 수 있도록 Tree 에서 저수명령어로 따라 하는 예를
보여.
git status
git status 명령은 렉토리와 Staging Aread의 상를 보여. Modified 이거나 Unstaged
일이 무엇인지 Staged 이지만 아직 하지 않은 일은 무엇인지 보여. Staging Area일을 내는
방법에 대한 트도 보여.
git status 명령은 일의 상태 확인하기에서 간하게 명한다. 이 명령은 이 책에서 주 많이 사용했지만 여기
명을 어나지 않는다.
git diff
git diff 명령은 이를 보고 을 때 사용한다. 렉토리와 Staging Area를 비할 수 있고(git
diff) Staing Area마지을 비할 수 있다(git diff --staged). 을 비할 수 있다(git
diff master branchB).
`git diff`StagedUnstaged 경 내용을 보기에서 처음 명한다. Staged 인 내용이 무엇이고
인 내용은 무엇인지 비하는 명한다.
가이드라인에서 --check 옵션으로 백문자가 못 입력되지 않았는지 인하는 방법을 소개한다.
내용인지 인하기에서 두 브랜치를 효율적으로 비할 수 있는 git diff A…B 명한다.
Merge을 보면 -b 옵션으로 백문자는 무시하고 비하는 것과 --theirs, --ours, --base 옵션으로
일의 상를 비하는 방법이 나있다.
마지으로 시작하기에서 서경 내용을 비하는 --submodule 옵션명한다.
git difftool
git difftool 명령은 순히 외부 diff 를 실. `git diff`Git에 들어 있는 기을 사용하는 것이고 외부
diff 를 비하고 을 때 사용한다.
이 명령은 StagedUnstaged 경 내용을 보기에서 명한다.
git commit
git commit 명령은 `git add`Staging Area은 모든 일을 커한다. 데이터이스에는 하나의 스냅샷으로
기록된다. 현 브랜치가 새 커을 가키게 한다.
에 대한 기적인 내용은 경사하기에서 다. -a 그를 주고 `git add`고 바로 커하는
것과 `-m`으로 커밋 메시지를 터로 넘기는 방법도 보여.
장 최근 을 수정하는 --amend 옵션돌리에서 명한다.
487
브랜무엇인가을 보면 `git commit`이 무엇을 하는지 게 하는지 명한다.
-S 그로 커에 서명하는 방법에 서명하기에서 명한다.
마지으로 에서 git commit 명령이 내부적으로 하는 일이 무엇이고 실제로 어떻게 구현돼 있는지 명한다.
git reset
git reset 명령은 되돌리(Undo) 명령이다. 어가 의하는 그대로라고 생각하면 된다. HEAD 포인터를 기는
것과 관련돼 있고 Staging Area(index)를 되돌릴 수 있고 --hard 옵션을 주면 렉토리도 되돌린. --hard
옵션못 사용하면 작업물어버수도 있기 때문에 이 명령을 이해하고 있어한다.
`git reset`은 무엇보다도 `git add`로 추가한 일을 Unstage 하는데 사용한다. 일 상Unstage
경하기에서 명한다.
Reset 히 알고 가기에서 이 명령을 전적으로 자세히 명한다.
git reset --hard 명령으로 Merge소할 수 있다. git merge --abort 로도 은 일을 할 수 있는데
이 명령은 git reset 명령어의 Wrapper. 이 내용은 Merge 소하기에서 명한다.
git rm
git rm 명령은 Staging Area렉토리에 있는 일을 제하는 데 사용한다. git add 명령과 비하게 일의
제를 Stage 하는 기이다.
제하기에서 git rm 명령을 자세히 명한다. Staging Area와 워렉토리 에서 일을 제하는 방법
--cached 옵션을 주고 Staging Area에 있는 일만 지우고 렉토리일은 방법명한다.
대부분은 에서 명한 대로 쓰지만, 이 책에서는 다게 사용한 예도 있다. git filter-branch 명령을
할 때 git rm 명령에 --ignore-unmatch 옵션을 주고 사용한다. 옵션제하려는 일이 없을 때 에러가
나지 않게 해. 스크트를 작성할 때는 유용하다.
git mv
git mv 명령은 일을 기고(이름을 경하고) 나서 새 일에 git add 명령을 실하고 이전 일에는 `git rm`
주는 명령이다.
이 명령은 일 이름 경하기에서 다.
git clean
git clean 명령은 렉토리에서 요없는 일을 제하는 명령이다. 이 명령으로 로 생긴 파일이나
일을 제할 때 편하다.
이 명령을 사용하는 상요한 옵션렉토리 소하기에서 다.
488
BranchMerge
여기서 소개하는 명령어만 알면 Branch를 사용하고 Merge 하는 일은 히 할 수 있다.
git branch
git branch 명령은 브랜치를 관리하는 도. 이 명령은 브랜치를 모보여주고 브랜치를 새로 만들고 브랜치를
제하고 브랜치 이름을 경한다.
Git 브랜에서 branch 명령을 명하는데 이 명령을 한 에 걸명한다. 브랜치를 만드는 것은 브랜
생성하기에서 명하고 브랜치를 보여주거나 제하는 기브랜관리에서 명한다.
git branch -u 명령으로 트브랜치를 만드는 것을 브랜치 추적에서 보여.
내부적으로 어일이 벌어지는지는 Git Refs에서 명한다.
git checkout
git checkout 명령은 브랜치를 경하고 해당 일을 렉토리사한다.
브랜치 이동하기에서 git branch 명령을 명하면서 이 명령도 명한다.
브랜치 추적에서 --track 옵션을 주고 트브랜치를 만드는 방법명한다.
돌 파Checkout해 이 명령에 `--conflict=diff3`을 주면 돌 표시된 일을 재할 수 있다.
git reset 명령과 관련된 내용은 Reset 히 알고 가기에서 명한다.
마지으로 `git checkout`이 어떻게 구현됐는지는 HEAD를 참고한다.
git merge
`git merge`는 다른 브랜치를 Checkout브랜치에 Merge 하는 명령이다. Merge 하고 나서 브랜치가
Merge 과를 가키도록 .
git merge 명령은 브랜치의 기에서 명한다. 이 책의 여러 에서 merge 명령을 사용하지만 브랜치의 기에서
명한 것에서 크게 어나지 않는다. git merge <branch> 명령을 실하면 해당 브랜치가 Merge 된다.
개 프로젝트 Fork부분에서 Squash 해서 Merge 하는 방법명한다. Merge 하는 브랜치의 히스토리
무시하고 새 커을 하나 만들어 Merge 하는 방법이다.
Merge에서는 -Xignore-space-change 옵션을 사용하는 방법이나 --abort 그로 Merge를 중하는
방법 등을 명한다.
Merge 하기 전에 서명을 사하는 방법명한다. GPG 서명은 에 서명하기에서 명한다.
마지으로 SubtreeMerge 하는 것은 Merge에서 배운다.
489
git mergetool
git mergetool 명령은 외부 Merge Helper를 실. Merge 하다가 문제가 생을 때 사용한다.
의 기에서 살을 보여주고 다른 Merge, Diff 사용하기에서 자신의 외부 Merge 정하는 방법
명한다.
git log
git log 명령은 프로젝트 히스토리를 시간의 순으로 보여. Ref를 따라 히스토리를 보여주는데 Ref를 한
개가 니라 여러 개 넘수도 있다. Ref를 넘주지 않으면 HEAD가 가키는 브랜치의 히스토리를 보여. 또 이
명령으로 여러 브랜치들 사이의 이를 커밋 단위로 볼 수 있다.
이 책에서 프로젝트 히스트를 보여때마다 이 명령을 사용한다고 도 된다.
히스토리 조회하기에서 이 명령을 게 다. -p` `--stat 옵션을 주면 각 커사이에 생긴 변화인할
수 있다. --pretty` `--oneline 옵션을 주면 히스토리를 좀 더 깔끔하게 볼 수 있다. 옵션Author
중심으로 히스토리를 보여.
브랜치 생성하기을 보면 --decorate 옵션을 주고 히스토리브랜치 포인터가 함보이도록 하는 방법이 나온다.
--graph 옵션을 추가하면 히스토리가 어떻게 진행됐는지도 볼 수 있다.
개 소모 팀위로 커키기에서 branchA..branchB 을 사용하는 방법명한다.
`branchB`에만 있고 `branchA`에는 없는 커만 걸러서 볼 수 있다. 위로 커키기에서 이 문을 다하게
합하는 방법명한다.
In Merge 로그Triple Dot에서 branchA…branchB 을 사용하는 방법명한다. 이 문은 둘 중 한에 속한
만 보여. --left-right 옵션을 주면 각각 어느 에 속한 것인지도 보여. Merge 로그에서는
할 때 유용한 --merge 옵션명한다. --cc 옵션을 사용하면 을 히스토리에 보여.
-g 옵션을 사용하면 브랜치를 오간 기록인 Reflog도 함보여. 이것은 RefLog로 가키기에서 명한다.
에서는 -S` `-L 옵션을 소개한다. 옵션을 사용하면 특정 코드에 대한 히스토리찾아볼 수 있다. 특정 함수의
히스토리를 보고 을 때 사용하면 유용하다.
에 서명하기에서 --show-signature 옵션을 사용하는 방법명한다. git log 명령에 이 옵션을 사용하면
의 서명 정보까지도 보여.
git stash
git stash 명령은 아직 하지 않은 일을 저하는 데 사용된다. 중인 렉토리를 저한다.
StashingCleaning에서 명한다.
git tag
git tag 명령은 히스토리에서 특정부분을 마크하는 기이다. 적으로 배포할 때 사용한다.
이 명령은 에서 자세히 명하고 릴리즈 버전에 그 달기에 보면 구체적인 사도 보여.
490
그에 GPG 서명을 하려면 -s 그를 주면 되고 -v 그를 주면 서명을 검증할 수 있다. 내 작에 서명하기에서
.
공유하고 업데이트하기
Git에는 크가 요한 명령어가 많지 않다. 거의 로데이터이스만으로 동작한다. 코드를 유하거나 가져올
요한 명령어가 개 있다. 이런 명령어는 모두 리모트 저소를 다루는 명령어다.
git fetch
git fetch 명령은 로데이터이스에 있는 것을 모트 저소의 모든 것을 가온다.
모트 저소를 Pull 하거나 Fetch 하기에서 이 명령을 명하고 모트 브랜에 보면 참고할 수 있는 예제가 더 있다.
프로젝트에 기여하기에도 좋은 예제가 많다.
Ref를 한 개만 가오는 방법Pull RequestRef에서 명하고 들에서 가오는 방법Bundle에서 명한다.
Fetch 하는 기Refspec을 수정하는 방법in Refspec에서 명한다. 원하는 대로 수정할 수 있다.
git pull
git pull 명령은 git fetch git merge 명령을 순서대로 실하는 것뿐이다. 서 해당 모트에서 Fetch
하고 현 브랜치로 Merge를 시도한다.
모트 저소를 Pull 하거나 Fetch 하기에서 이 명령을 사용하는 방법을 다고 정히 무엇을 Merge 하는 지는 모트
소 살펴보기에서 명한다.
Rebase 한 것을 다시 Rebase 하기에서 그 어렵다는 Rebase를 다루는 방법명한다.
URL을 주고 한 Pull 수 있다는 것을 모트 브랜치로부터 합하기에서 명한다.
--verify-signatures 옵션을 주면 Pull 할 때 커PGP 서명을 검증한다. PGP 서명은 에 서명하기에서
명한다.
git push
git push 명령은 모트에는 없지만, 에는 있는 커을 계하고 나서 그 이만큼만 Push 한다. Push를 하려면
소에 대한 쓰기 한이 요하고 인돼야 한다.
모트 저소에 Push 하기에서 git push 명령으로 브랜치를 원소에 Push 하는 방법명한다.
브랜치를 하나씩 골라서 Push 하는 방법Push 하기에서 명한다. 자동으로 Push 하도록 트브랜치를 정하는
방법브랜치 추적에서 명한다. git push --delete 명령으로 원서버의 브랜치를 제하는 방법모트
브랜에서 명한다.
프로젝트에 기여하기에서는 `git push`를 주구장창 사용한다. 모트를 여러 개 사용해서 브랜치에 작한 내용을
유하는 것을 보여.
--tags 옵션을 주고 그를 Push 하는 방법유하기에서 명한다.
491
의 코드를 수정했을 때는 --recurse-submodules 옵션이 좋다. 프로젝트를 Push 할 때 서Push
할 게 있으면 서부터 Push 우 편하다. 옵션수정 사유하기에서 명한다.
기타 에서 pre-push 에 대해서 명했다. Push 해도 되는지 검증하는 스크트를 정하면 규칙
도록 Push검증할 수 있다.
적인 이름 규칙에 따라서 Push 하는 것이 니라 Refspec을 사용해서 원하는 이름으로 Push 하는 것도 가하다.
이것은 Refspec Push 하기에서 명한다.
git remote
git remote 명령은 원정인 모트의 관리 . URL 대신 “origin” 처럼 이름을 게 지을 수 있다.
URL대신 모트 이름을 사용한다. git remote 명령으로 이 모트를 여러 개 만들어 관리할 수 있다.
모트를 회하고 추가하고 제하고 수정하는 방법모트 저에서 잘 설명한다.
이 명령은 git remote add <name> <url> 형식으로 사용하고 이 책에서 자주 사용된다.
git archive
git archive 명령은 프로젝트 스냅샷브 파일로 만들어 .
릴리비하기에서 명하는데 프로젝트를 Tarball로 만들어 유할 때 사용한다.
git submodule
git submodule 명령은 저에서 다른 저소를 관리하는 데 사용한다. 라이나 특정 형식소스 일을
로 사용할 수 있다. submodule 명령에 있는 add, update, sync 등의 하위 명령어로 서관리할 수
있다.
이 명령은 에서 명한다.
보기와 비
git show
git show 명령은 Git 를 사람이 을 수 있도록 요해서 보여. 그나 커정보를 보고 을 때 이 명령을
사용한다.
Annotated 을 보면 Annotated 그의 정보를 보여주는 예제가 나온다.
비전 회하기에서 이 명령을 사용하는 것을 보여.
Merge 하다가 을 때 특정 버전의 일 내용을 `git show`내 볼 수 있다. 수동으로 Merge 하기에서 이
명한다.
492
git shortlog
git shortlog 명령은 git log 명령의 과를 요해서 보여 다고 생각하면 된다. 옵션git log 명령의 것과
우 비하다. 이 명령은 Author 로 커어서 보여.
이 명령은 Changelog 일을 만들 때 유용한 데 Shortlog 보기에서 보여.
git describe
git describe 명령은 커관련된 정보를 잘 조합해서 사람이 을 수 있는 스트을 만들어 . SHA-1처럼
식별 하고 사람이 이해할 수 있는 정보가 요할 때 사용한다.
드넘버 만들기릴리비하기에서 git describe 명령을 명한다. 이 명령으로 배포 일의 이름을 는다.
Debugging
Git에는 디버용 명령어도 있다. 가 버그를 만들었는지 제 어디서 생는지 찾아내는 데 도움이 된다.
git bisect
`git bisect`히 유용하다. 진 탐색 알고을 사용해서 버그나 문제가 생을 쉽게 을 수 있다.
이 명령은 진 탐색에서 잘 설명한다.
git blame
`git blame`일의 각 라인을 가 마지으로 수정했는지 보여. 서 특정 코드에 대해 금한 게 있을 때
누구에게 할지 바로 알 수 있다.
이 명령은 일 어노(Blame)에서 다.
git grep
소스 코드에서 스트이나 정규표현식을 수 있다. git grep 명령을 사용하면 예전 소스 코드까지 는다.
Git Grep에서 이 명령을 명한다.
Patch 하기
음을 Patch 음처럼 다루는 것이 편할 때가 있다. 때를 위해서 Git에는 커밋 몇 개만 추출하고 적용하고
관리하는 명령어가 있다. 이 명령어는 브랜치를 관리할 때 좋다.
git cherry-pick
git cherry-pick 명령은 커하나만 가져올 때 사용한다. 현 브랜치의 새 커으로 적용된다. 이 명령은 브랜치를
통째Merge 하기 보다 커개 정도만 Merge 하고 을 때 좋다.
이 명령으로 커을 고는 것은 RebaseCherry-Pick 크플로에서 명한다.
493
git rebase
git rebase 명령은 `check-pick`을 여러 해 주는 것과 . 연결된 커을 그 순서대로 한Cherry-pick
해온다.
RebaseRebase 하기에서 명한다. 미 공개한 브랜치를 Rebase 할 때 생기는 문제도 다.
Replace에서는 히스토리소로 분하는 것을 보여주는데 여기서 --onto 옵션을 사용한다.
Rerere에서 Rebase 하면서 발생한 을 어떻게 해하는지 보여.
-i 옵션을 주고 이 명령을 실하면 대화형으로 실할 수 있다. 밋 메시지를 여러 개 수정하기에서 명한다.
git revert
git revert 명령은 git cherry-pick 명령의 대로 볼 수 있다. 해당 커을 되돌리는 커을 새로 생성한다.
돌리에서 Merge 을 되돌리는 것을 보여.
Email
스트로 관리하는 프로젝트가 많이 있다. Git 프로젝트 자도 그. Git에는 이일로 작하기 쉽게 만들어
주는 도가 들어 있다. Patch를 생성해서 이일을 보내고 스에서 Patch를 적용하는 과정을 도와준.
git apply
git apply 명령은 git diff 명령으로 생성한 Patch를 적용하는 명령이다. GNU diff 명령으로 생성한 Patch
하다. 간의 이는 있지만 patch 명령어하다.
이 명령을 사용하는 상과 어떻게 사용하는지 일로 Patch를 적용하기에서 명한다.
git am
git am 명령으로 이일 인스에 든 mbox Patch를 적용할 수 있다. 일로 치를 주고을 때 유용하다.
git am 제 어떻게 사용하는지는 am 명령을 사용하는 방법에서 다. --resolved, -i, -3 옵션 사용
명한다.
git am 명령을 사용할 때 정할 수 있는 크플로 에서 다.
이 명령으로 GitHub Pull RequestPatch도 적용할 수 있는데 일 알에서 명한다.
git format-patch
git format-patch 명령은 Patchmbox 으로 생성하는 데 사용한다. 생성 한 치를 쉽게 스트로
수 있다.
`git format-patch`로 프로젝트에 기여하는 예제를 개 프로젝트일을 관리에서 보여.
494
git imap-send
git imap-send 명령은 `git format-patch`로 생성한 일을 IMAP drafts 더에 .
git imap-send 명령으로 예제는 개 프로젝트일을 관리에서 살펴. 치를 보내서
프로젝트에 기여해보는 예제다.
git send-email
git send-email 명령은 git format-patch 명령으로 생성한 Patch를 이일로 보내는 데 사용한다.
개 프로젝트일을 관리에서 git send-email 명령으로 치를 보내서 다른 프로젝트에 기여하는
것을 보여.
git request-pull
git request-pull 명령은 일 바디를 생성해주는 명령이다. 서 쉽게 다른 사람에게 일을 보수 있다.
브랜치에 커하고 Push 해 놓은 상가에게 알때 유용하다. Patch 는 이일로 보내지 않고 정보만
해 보수 있다. 이 명령의 과를 일로 보내면 된다.
개 프로젝트 Fork에서 git request-pull 명령을 사용하는 것을 보여.
다른 버전 관리 시스템
Git에는 다른 버전 관리 시스을 지원하는 명령어도 있다.
git svn
git svn 명령은 GitSubversion라이트로 사용하는 명령이다. Git으로 Subversion 서버에 있는
Checkout 할 수 있다.
GitSubversion에서 자세히 명한다.
git fast-import
버전 관리 시스을 가지 않고 데이터를 Git으로 가져올 수 있는 다목적 명령어도 있다. 버전 관리 시스뿐만 니라
다른 형식으로 관리하던 데이터도 가져올 수 있다. git fast-import 명령은 다른 포의 데이터를 쉽게 할 수
있게 해.
Importer 만들기에서 이 명령을 명한다.
관리
관리자는 Git 소에 문제가 생기면 해한다. Git은 이때 요한 명령어도 제한다.
git gc
`git gc`는 저소에 요없는 일을 제하고 일을 하는 “Garbage Collection” 명령이다.
495
접 실도 되지만 Git이 자동으로 실. 자세한 명은 운영에서 한다.
git fsck
`git fsck`Git 데이터이스에 문제가 없는지 사해.
데이터 복구에서 Dangling 명한다.
git reflog
git reflog 명령은 HEAD가 가리켰던 커의 로그를 보여. 히스토리를 재작성해서 어버을 때
유용하다.
RefLog로 가키기에서 이 명령을 명한다. git log 명령에 -g 옵션을 주면 git log 명령의 과처럼 Reflog
출력한다.
어버린 브랜치를 복구하는 데이터 복구에서도 명한다.
git filter-branch
git filter-branch 명령은 커치를 수정하는 데 사용한다. 히스토리에서 일을 제하거나 디렉토리
구조경하는 데 사용한다.
모든 커에서 일을 제거하기에서 --commit-filter, --subdirectory-filter, --tree-filter
옵션 사용명한다.
Git-p4, TFS에서는 다른 버전 관리 시스에서 가온 데이터이스를 바로 는 데 사용한다.
Plumbing 명령어
이 책에서는 저수Plumbing 명령어도 많이 소개한다.
Pull RequestRef에서는 서버에 있는 저수Ref회하는 ls-remote 명령을 소개한다.
수동으로 Merge 하기Rerere, Index에서 사용하는 `ls-files`Staging Area의 저수모습을 보여.
rev-parse 명령은 가키는 개SHA-1 을 보여. 브랜치로 가키기에서 다.
저수명령인 Plumbing 명령은 거의 Git의 내부에서 명한다. Plumbing 명령에는 이 에서만 명하려고 했다. 다른
에서는 대한 Plumbing 명령어는 사용하지 않으려고 노력했다.
496
Index
@
$EDITOR, 332
$VISUAL
see $EDITOR, 332
.NET, 478
.gitignore, 334
ì0í, 90
ì1í, 90
A
Apache, 114
Apple, 479
aliases, 57
archiving, 348
attributes, 341
autocorrect, 334
B
Bazaar, 407
BitKeeper, 12
bash, 468
binary files, 341
bitnami, 117
branches, 60
basic workflow, 67
creating, 62
deleting remote, 91
diffing, 153
long-running, 78
managing, 76
merging, 72
remote, 82, 152
switching, 64
topic, 79, 149
tracking, 89
upstream, 89
build numbers, 161
C
C, 474
C#, 478
CRLF, 17
CVS, 9
Cocoa, 479
color, 335
commit templates, 332
contributing, 125
private managed team, 135
private small team, 127
public large project, 145
public small project, 141
credential caching, 17
credentials, 325
crlf, 339
D
difftool, 335
distributed git, 122
E
Eclipse, 467
editor
changing default, 34
email, 147
applying patches from, 149
excludes, 334, 421
F
files
moving, 37
removing, 35
forking, 124, 169
G
GPG, 333
GUIs, 461
Git as a client, 363
GitHub, 164
API, 208
Flow, 170
organizations, 200
pull requests, 173
user accounts, 164
GitHub for Mac, 463
GitHub for Windows, 463
GitLab, 117
GitWeb, 115
Go, 483
497
Graphical tools, 461
git commands
add, 26, 26, 27
am, 150
apply, 149
archive, 162
branch, 62, 76
checkout, 64
cherry-pick, 158
clone, 24
commit, 34, 60
config, 19, 21, 34, 57, 147, 331
credential, 325
daemon, 112
describe, 161
diff, 30
check, 126
fast-import, 413
fetch, 49
fetch-pack, 446
filter-branch, 411
format-patch, 145
gitk, 461
gui, 461
help, 21, 111
http-backend, 113
init, 23, 26
bare, 107, 110
instaweb, 115
log, 38
merge, 70
squash, 144
mergetool, 75
p4, 393, 410
pull, 49
push, 49, 55, 87
rebase, 92
receive-pack, 444
remote, 47, 48, 50, 51
request-pull, 142
rerere, 160
send-pack, 444
shortlog, 162
show, 54
show-ref, 365
status, 25, 33
svn, 363
tag, 52, 53, 55
upload-pack, 446
git-svn, 363
gitk, 461
go-git, 483
H
hooks, 350
post-update, 104
I
IRC, 22
Importing
from Bazaar, 407
from Mercurial, 404
from Perforce, 410
from Subversion, 402
from TFS, 412
from others, 413
Interoperation with other VCSs
Mercurial, 374
Perforce, 385
Subversion, 363
ignoring files, 29
integrating work, 154
J
java, 479
jgit, 479
K
keyword expansion, 345
L
Linus Torvalds, 12
Linux, 12
installing, 16
libgit2, 474
line endings, 339
log filtering, 43
log formatting, 40
498
M
Mac
installing, 16
Mercurial, 374, 404
Migrating to Git, 402
Mono, 478
maintaining a project, 148
master, 61
mergetool, 335
merging, 72
conflicts, 73
strategies, 350
vs. rebasing, 101
O
Objective-C, 479
origin, 82
P
Perforce, 9, 12, 385, 410
Git Fusion, 385
Powershell, 17
Python, 479
pager, 333
policy example, 353
posh-git, 471
powershell, 471
protocols
SSH, 105
dumb HTTP, 104
git, 106
local, 102
smart HTTP, 103
pulling, 90
pushing, 87
R
Ruby, 475
rebasing, 91
perils of, 96
vs. merging, 101
references
remote, 82
releasing, 162
rerere, 160
S
SHA-1, 14
SSH keys, 108
with GitHub, 165
Subversion, 9, 12, 363, 402
serving repositories, 102
GitLab, 117
GitWeb, 115
HTTP, 113
SSH, 108
git protocol, 111
shell prompts
bash, 468
powershell, 471
zsh, 469
staging area
skipping, 35
T
TFS, 412
tab completion
bash, 468
powershell, 471
zsh, 469
tags, 52, 160
annotated, 53
lightweight, 54
signing, 160
V
Visual Studio, 466
version control, 8
centralized, 9
distributed, 10
local, 8
W
Windows
installing, 17
whitespace, 338
workflows, 122
centralized, 122
499
dictator and lieutenants, 124
integration manager, 123
merging, 154
merging (large), 157
rebasing and cherry-picking, 158
X
Xcode, 16
Z
zsh, 469
500